From a0082e6886eddfe3352bb1b283ffb38f60660677 Mon Sep 17 00:00:00 2001 From: ji_xinliu Date: Tue, 15 Oct 2024 16:22:06 +0800 Subject: [PATCH] =?UTF-8?q?angle=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ji_xinliu --- include/platform/FeaturesGL_autogen.h | 11 + include/platform/FrontendFeatures_autogen.h | 5 - include/platform/frontend_features.json | 8 - include/platform/gl_features.json | 16 + include/platform/vk_features.json | 9 + .../ANGLE_features.json | 14 +- src/compiler.gni | 4 +- src/compiler/translator/Common.h | 16 + src/compiler/translator/Compiler.cpp | 20 +- src/compiler/translator/OutputSPIRV.cpp | 2 +- src/compiler/translator/ParseContext.cpp | 2 + .../ValidateTypeSizeLimitations.cpp | 11 +- .../ScalarizeVecAndMatConstructorArgs.cpp | 223 ----------- .../gl/ScalarizeVecAndMatConstructorArgs.cpp | 378 ++++++++++++++++++ .../ScalarizeVecAndMatConstructorArgs.h | 19 +- .../tree_util/IntermNodePatternMatcher.cpp | 41 -- .../tree_util/IntermNodePatternMatcher.h | 4 - src/compiler/translator/util.cpp | 3 + src/libANGLE/Display.cpp | 3 - src/libANGLE/Shader.cpp | 5 - src/libANGLE/renderer/gl/BufferGL.cpp | 5 + src/libANGLE/renderer/gl/BufferGL.h | 1 + src/libANGLE/renderer/gl/ShaderGL.cpp | 5 + src/libANGLE/renderer/gl/VertexArrayGL.cpp | 20 +- src/libANGLE/renderer/gl/renderergl_utils.cpp | 6 + src/libANGLE/renderer/vulkan/BufferVk.cpp | 8 +- src/libANGLE/renderer/vulkan/RendererVk.cpp | 3 + src/libANGLE/renderer/vulkan/Suballocation.h | 7 + src/libANGLE/renderer/vulkan/TextureVk.cpp | 6 +- .../renderer/vulkan/vk_cache_utils.cpp | 26 +- src/libANGLE/renderer/vulkan/vk_cache_utils.h | 1 + src/libANGLE/renderer/vulkan/vk_helpers.cpp | 16 +- src/libANGLE/renderer/vulkan/vk_helpers.h | 4 +- .../angle_end2end_tests_expectations.txt | 8 +- src/tests/angle_unittests.gni | 1 - ...ScalarizeVecAndMatConstructorArgs_test.cpp | 138 ------- src/tests/gl_tests/GLSLTest.cpp | 260 ++++++++++-- src/tests/gl_tests/TransformFeedbackTest.cpp | 45 +++ src/tests/gl_tests/UniformBufferTest.cpp | 44 ++ src/tests/gl_tests/WebGLCompatibilityTest.cpp | 182 ++++++++- util/angle_features_autogen.cpp | 1 + util/angle_features_autogen.h | 1 + 42 files changed, 1046 insertions(+), 536 deletions(-) delete mode 100644 src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp create mode 100644 src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.cpp rename src/compiler/translator/tree_ops/{ => gl}/ScalarizeVecAndMatConstructorArgs.h (58%) delete mode 100644 src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp diff --git a/include/platform/FeaturesGL_autogen.h b/include/platform/FeaturesGL_autogen.h index 3f82aa6..e3ee3d6 100644 --- a/include/platform/FeaturesGL_autogen.h +++ b/include/platform/FeaturesGL_autogen.h @@ -509,6 +509,17 @@ struct FeaturesGL : FeatureSetBase "supportsShaderPixelLocalStorageEXT", FeatureCategory::OpenGLFeatures, "Backend GL context supports EXT_shader_pixel_local_storage extension", &members, "http://anglebug.com/7279"}; + + FeatureInfo scalarizeVecAndMatConstructorArgs = { + "scalarizeVecAndMatConstructorArgs", FeatureCategory::OpenGLWorkarounds, + "Rewrite vec/mat constructors to work around driver bugs", &members, + "http://crbug.com/1420130"}; + + FeatureInfo ensureNonEmptyBufferIsBoundForDraw = { + "ensureNonEmptyBufferIsBoundForDraw", FeatureCategory::OpenGLFeatures, + "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero " + "divisor.", + &members, "http://crbug.com/1456243"}; }; inline FeaturesGL::FeaturesGL() = default; diff --git a/include/platform/FrontendFeatures_autogen.h b/include/platform/FrontendFeatures_autogen.h index f9677d6..8755051 100644 --- a/include/platform/FrontendFeatures_autogen.h +++ b/include/platform/FrontendFeatures_autogen.h @@ -35,11 +35,6 @@ struct FrontendFeatures : FeatureSetBase &members, }; - FeatureInfo scalarizeVecAndMatConstructorArgs = { - "scalarizeVecAndMatConstructorArgs", FeatureCategory::FrontendWorkarounds, - "Always rewrite vec/mat constructors to be consistent", &members, - "http://crbug.com/1165751"}; - FeatureInfo disableProgramBinary = {"disableProgramBinary", FeatureCategory::FrontendFeatures, "Disable support for GL_OES_get_program_binary", &members, "http://anglebug.com/5007"}; diff --git a/include/platform/frontend_features.json b/include/platform/frontend_features.json index 57ebf1c..9c492a1 100644 --- a/include/platform/frontend_features.json +++ b/include/platform/frontend_features.json @@ -22,14 +22,6 @@ "On some GPUs, program binaries don't contain transform feedback varyings" ] }, - { - "name": "scalarize_vec_and_mat_constructor_args", - "category": "Workarounds", - "description": [ - "Always rewrite vec/mat constructors to be consistent" - ], - "issue": "http://crbug.com/1165751" - }, { "name": "disable_program_binary", "category": "Features", diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json index 0b85f81..6e23def 100644 --- a/include/platform/gl_features.json +++ b/include/platform/gl_features.json @@ -707,6 +707,22 @@ "Backend GL context supports EXT_shader_pixel_local_storage extension" ], "issue": "http://anglebug.com/7279" + }, + { + "name": "scalarize_vec_and_mat_constructor_args", + "category": "Workarounds", + "description": [ + "Rewrite vec/mat constructors to work around driver bugs" + ], + "issue": "http://crbug.com/1420130" + }, + { + "name": "ensure_non_empty_buffer_is_bound_for_draw", + "category": "Features", + "description": [ + "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero divisor." + ], + "issue": "http://crbug.com/1456243" } ] } diff --git a/include/platform/vk_features.json b/include/platform/vk_features.json index 083571c..279e2bd 100644 --- a/include/platform/vk_features.json +++ b/include/platform/vk_features.json @@ -1206,6 +1206,15 @@ "description":["Reset command buffer in async thread."], "issue": "https://issuetracker.google.com/255411748" }, + { + "name": "wrap_switch_in_if_true", + "category": "Workarounds", + "description": [ + "On some drivers, nested switch statements are mishandled which can be worked around ", + "by wrapping them in if(true)" + ], + "issue": "http://crbug.com/350528343" + }, { "name": "use_reset_command_buffer_bit_for_secondary_pools", "category": "Workarounds", diff --git a/scripts/code_generation_hashes/ANGLE_features.json b/scripts/code_generation_hashes/ANGLE_features.json index e6a6469..d9aee7f 100644 --- a/scripts/code_generation_hashes/ANGLE_features.json +++ b/scripts/code_generation_hashes/ANGLE_features.json @@ -2,27 +2,27 @@ "include/platform/FeaturesD3D_autogen.h": "bdce5cac5c70e04fd39e9cf8c6969292", "include/platform/FeaturesGL_autogen.h": - "331b1660b3982f6540e362764df26021", + "0a6c2358c29532f9d94376c666433bd2", "include/platform/FeaturesMtl_autogen.h": "4c7e4b74b49b88542820b8ab76b131ca", "include/platform/FeaturesVk_autogen.h": "38ce2b494fac31f1b866d75be8330bea", "include/platform/FrontendFeatures_autogen.h": - "391ebdb90344949e7060cb867a456511", + "00e9bb2fa7a11dbe9a8c2440fd9dede7", "include/platform/d3d_features.json": "c3f7694511855304b3f678a6ad461d1e", "include/platform/frontend_features.json": - "db98716ec9e23fc17f32bf9bc53cc331", + "bd0718d422f62e8997c27773c4180a52", "include/platform/gen_features.py": "062989f7a8f3ff3b383f98fc8908dc33", "include/platform/gl_features.json": - "cef92e7ede4c824b8bae37123401d354", + "5840a20d950ed1498e79a4ffe433e16b", "include/platform/mtl_features.json": "2472b8a7eb65fc243fc9380b8a1d8dcd", "include/platform/vk_features.json": "bc04d0a45f9ecb1bec30aef49d73b583", "util/angle_features_autogen.cpp": - "3b5766e72ca387ba416eefe956fbd83e", + "810a35a106b997eca3d461b0f98a282c", "util/angle_features_autogen.h": - "18b03cfa47c1fc3cda5d66de4de7ab51" -} \ No newline at end of file + "c90a6c7bb25ba0e9876d65c75a33f597" +} diff --git a/src/compiler.gni b/src/compiler.gni index 1cd408a..1125d59 100644 --- a/src/compiler.gni +++ b/src/compiler.gni @@ -181,8 +181,6 @@ angle_translator_sources = [ "src/compiler/translator/tree_ops/RewriteStructSamplers.h", "src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp", "src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h", - "src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp", - "src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h", "src/compiler/translator/tree_ops/SeparateDeclarations.cpp", "src/compiler/translator/tree_ops/SeparateDeclarations.h", "src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp", @@ -199,6 +197,7 @@ angle_translator_sources = [ "src/compiler/translator/tree_ops/gl/ClampFragDepth.h", "src/compiler/translator/tree_ops/gl/RegenerateStructNames.h", "src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.h", + "src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.h", "src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.h", "src/compiler/translator/tree_util/AsNode.h", "src/compiler/translator/tree_util/BuiltIn.h", @@ -269,6 +268,7 @@ angle_translator_glsl_sources = [ "src/compiler/translator/tree_ops/gl/ClampFragDepth.cpp", "src/compiler/translator/tree_ops/gl/RegenerateStructNames.cpp", "src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.cpp", + "src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.cpp", "src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.cpp", ] angle_translator_glsl_apple_sources = [ diff --git a/src/compiler/translator/Common.h b/src/compiler/translator/Common.h index abbbda3..bb2f539 100644 --- a/src/compiler/translator/Common.h +++ b/src/compiler/translator/Common.h @@ -112,6 +112,22 @@ class TUnorderedMap : public std::unordered_map, class CMP = std::equal_to> +class TUnorderedSet : public std::unordered_set> +{ + public: + POOL_ALLOCATOR_NEW_DELETE + typedef pool_allocator tAllocator; + + TUnorderedSet() : std::unordered_set() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TUnorderedSet(const tAllocator &a) + : std::unordered_set( + std::unordered_set::key_compare(), + a) + {} +}; + template > class TMap : public std::map>> { diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp index 5a53fb4..f4c6910 100644 --- a/src/compiler/translator/Compiler.cpp +++ b/src/compiler/translator/Compiler.cpp @@ -47,7 +47,6 @@ #include "compiler/translator/tree_ops/RemoveInvariantDeclaration.h" #include "compiler/translator/tree_ops/RemoveUnreferencedVariables.h" #include "compiler/translator/tree_ops/RewritePixelLocalStorage.h" -#include "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h" #include "compiler/translator/tree_ops/SeparateDeclarations.h" #include "compiler/translator/tree_ops/SimplifyLoopConditions.h" #include "compiler/translator/tree_ops/SplitSequenceOperator.h" @@ -57,6 +56,7 @@ #include "compiler/translator/tree_ops/gl/ClampFragDepth.h" #include "compiler/translator/tree_ops/gl/RegenerateStructNames.h" #include "compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.h" +#include "compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.h" #include "compiler/translator/tree_ops/gl/UseInterfaceBlockFields.h" #include "compiler/translator/tree_util/BuiltIn.h" #include "compiler/translator/tree_util/IntermNodePatternMatcher.h" @@ -398,9 +398,10 @@ bool TCompiler::shouldRunLoopAndIndexingValidation(const ShCompileOptions &compi bool TCompiler::shouldLimitTypeSizes() const { - // WebGL shaders limit the size of variables' types in shaders, - // including arrays, structs and interface blocks. - return IsWebGLBasedSpec(mShaderSpec); + // Prevent unrealistically large variable sizes in shaders. This works around driver bugs + // around int-size limits (such as 2GB). The limits are generously large enough that no real + // shader should ever hit it. + return true; } bool TCompiler::Init(const ShBuiltInResources &resources) @@ -996,17 +997,12 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, } } - int simplifyScalarized = compileOptions.scalarizeVecAndMatConstructorArgs - ? IntermNodePatternMatcher::kScalarizedVecOrMatConstructor - : 0; - // 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. if (!SimplifyLoopConditions(this, root, IntermNodePatternMatcher::kMultiDeclaration | - IntermNodePatternMatcher::kArrayLengthMethod | - simplifyScalarized, + IntermNodePatternMatcher::kArrayLengthMethod, &getSymbolTable())) { return false; @@ -1030,8 +1026,7 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, mValidateASTOptions.validateMultiDeclarations = true; - if (!SplitSequenceOperator(this, root, - IntermNodePatternMatcher::kArrayLengthMethod | simplifyScalarized, + if (!SplitSequenceOperator(this, root, IntermNodePatternMatcher::kArrayLengthMethod, &getSymbolTable())) { return false; @@ -1041,6 +1036,7 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, { return false; } + // Fold the expressions again, because |RemoveArrayLengthMethod| can introduce new constants. if (!FoldExpressions(this, root, &mDiagnostics)) { diff --git a/src/compiler/translator/OutputSPIRV.cpp b/src/compiler/translator/OutputSPIRV.cpp index 15b65e7..6a1e808 100644 --- a/src/compiler/translator/OutputSPIRV.cpp +++ b/src/compiler/translator/OutputSPIRV.cpp @@ -1745,7 +1745,7 @@ spirv::IdRef OutputSPIRVTraverser::createConstructorMatrixFromMatrix( // ... // %m = OpCompositeConstruct %matNxM %c0 %c1 %c2 ... // - // - Otherwise, an identity matrix is created and super imposed by m: + // - Otherwise, an identity matrix is created and superimposed by m: // // %c0 = OpCompositeConstruct %vecM %m[0][0] %m[0][1] %0 %0 // %c1 = OpCompositeConstruct %vecM %m[1][0] %m[1][1] %0 %0 diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp index c01e5db..be1bac9 100644 --- a/src/compiler/translator/ParseContext.cpp +++ b/src/compiler/translator/ParseContext.cpp @@ -42,8 +42,10 @@ struct IsOpaqueFunc { bool operator()(TBasicType type) { return IsOpaqueType(type); } }; + template bool ContainsOpaque(const TStructure *structType); + template bool ContainsOpaque(const TType &type) { diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp index 007b8ea..b528bd6 100644 --- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp +++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp @@ -7,6 +7,7 @@ #include "compiler/translator/ValidateTypeSizeLimitations.h" #include "angle_gl.h" +#include "common/mathutil.h" #include "compiler/translator/Diagnostics.h" #include "compiler/translator/Symbol.h" #include "compiler/translator/SymbolTable.h" @@ -23,11 +24,10 @@ namespace // Arbitrarily enforce that all types declared with a size in bytes of over 2 GB will cause // compilation failure. // -// For local and global variables, the limit is much lower (64KB) as that much memory won't fit in +// For local and global variables, the limit is much lower (16MB) as that much memory won't fit in // the GPU registers anyway. constexpr size_t kMaxVariableSizeInBytes = static_cast(2) * 1024 * 1024 * 1024; -constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast(64) * 1024; -constexpr size_t kMaxTotalPrivateVariableSizeInBytes = static_cast(16) * 1024 * 1024; +constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast(16) * 1024 * 1024; // Traverses intermediate tree to ensure that the shader does not // exceed certain implementation-defined limits on the sizes of types. @@ -186,7 +186,8 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser void validateTotalPrivateVariableSize() { - if (mTotalPrivateVariablesSize > kMaxTotalPrivateVariableSizeInBytes) + if (mTotalPrivateVariablesSize.ValueOrDefault(std::numeric_limits::max()) > + kMaxPrivateVariableSizeInBytes) { mDiagnostics->error( TSourceLoc{}, @@ -304,7 +305,7 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser TDiagnostics *mDiagnostics; std::vector mLoopSymbolIds; - size_t mTotalPrivateVariablesSize; + angle::base::CheckedNumeric mTotalPrivateVariablesSize; }; } // namespace diff --git a/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp b/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp deleted file mode 100644 index 4eab90e..0000000 --- a/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// -// Copyright 2002 The ANGLE Project Authors. All rights reserved. -// 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 "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h" -#include "common/debug.h" - -#include - -#include "angle_gl.h" -#include "common/angleutils.h" -#include "compiler/translator/Compiler.h" -#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" -#include "compiler/translator/tree_util/IntermNode_util.h" -#include "compiler/translator/tree_util/IntermTraverse.h" -#include "compiler/translator/util.h" - -namespace sh -{ - -namespace -{ - -TIntermBinary *ConstructVectorIndexBinaryNode(TIntermTyped *symbolNode, int index) -{ - return new TIntermBinary(EOpIndexDirect, symbolNode, CreateIndexNode(index)); -} - -TIntermBinary *ConstructMatrixIndexBinaryNode(TIntermTyped *symbolNode, int colIndex, int rowIndex) -{ - TIntermBinary *colVectorNode = ConstructVectorIndexBinaryNode(symbolNode, colIndex); - - return new TIntermBinary(EOpIndexDirect, colVectorNode, CreateIndexNode(rowIndex)); -} - -class ScalarizeArgsTraverser : public TIntermTraverser -{ - public: - ScalarizeArgsTraverser(TSymbolTable *symbolTable) - : TIntermTraverser(true, false, false, symbolTable), - mNodesToScalarize(IntermNodePatternMatcher::kScalarizedVecOrMatConstructor) - {} - - protected: - bool visitAggregate(Visit visit, TIntermAggregate *node) override; - bool visitBlock(Visit visit, TIntermBlock *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 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. - TIntermTyped *createTempVariable(TIntermTyped *original); - - std::vector mBlockStack; - - IntermNodePatternMatcher mNodesToScalarize; -}; - -bool ScalarizeArgsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) -{ - ASSERT(visit == PreVisit); - if (mNodesToScalarize.match(node, getParentNode())) - { - if (node->getType().isVector()) - { - scalarizeArgs(node, false, true); - } - else - { - ASSERT(node->getType().isMatrix()); - scalarizeArgs(node, true, false); - } - } - return true; -} - -bool ScalarizeArgsTraverser::visitBlock(Visit visit, TIntermBlock *node) -{ - 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()) - { - 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 originalArgs(*sequence); - sequence->clear(); - for (TIntermNode *originalArgNode : originalArgs) - { - ASSERT(size > 0); - TIntermTyped *originalArg = originalArgNode->getAsTyped(); - ASSERT(originalArg); - TIntermTyped *argVariable = createTempVariable(originalArg); - if (originalArg->isScalar()) - { - sequence->push_back(argVariable); - size--; - } - else if (originalArg->isVector()) - { - if (scalarizeVector) - { - int repeat = std::min(size, originalArg->getNominalSize()); - size -= repeat; - for (int index = 0; index < repeat; ++index) - { - TIntermBinary *newNode = - ConstructVectorIndexBinaryNode(argVariable->deepCopy(), index); - sequence->push_back(newNode); - } - } - else - { - sequence->push_back(argVariable); - size -= originalArg->getNominalSize(); - } - } - else - { - ASSERT(originalArg->isMatrix()); - if (scalarizeMatrix) - { - int colIndex = 0, rowIndex = 0; - int repeat = std::min(size, originalArg->getCols() * originalArg->getRows()); - size -= repeat; - while (repeat > 0) - { - TIntermBinary *newNode = - ConstructMatrixIndexBinaryNode(argVariable->deepCopy(), colIndex, rowIndex); - sequence->push_back(newNode); - rowIndex++; - if (rowIndex >= originalArg->getRows()) - { - rowIndex = 0; - colIndex++; - } - repeat--; - } - } - else - { - sequence->push_back(argVariable); - size -= originalArg->getCols() * originalArg->getRows(); - } - } - } -} - -TIntermTyped *ScalarizeArgsTraverser::createTempVariable(TIntermTyped *original) -{ - ASSERT(original); - - TType *type = new TType(original->getType()); - type->setQualifier(EvqTemporary); - - // The precision of the constant must have been retained (or derived), which will now apply to - // the temp variable. In some cases, the precision cannot be derived, so use the constant as - // is. For example, in the following standalone statement, the precision of the constant 0 - // cannot be determined: - // - // mat2(0, bvec3(m)); - // - if (IsPrecisionApplicableToType(type->getBasicType()) && type->getPrecision() == EbpUndefined) - { - return original; - } - - TVariable *variable = CreateTempVariable(mSymbolTable, type); - - ASSERT(mBlockStack.size() > 0); - TIntermSequence &sequence = mBlockStack.back(); - TIntermDeclaration *declaration = CreateTempInitDeclarationNode(variable, original); - sequence.push_back(declaration); - - return CreateTempSymbolNode(variable); -} - -} // namespace - -bool ScalarizeVecAndMatConstructorArgs(TCompiler *compiler, - TIntermBlock *root, - TSymbolTable *symbolTable) -{ - ScalarizeArgsTraverser scalarizer(symbolTable); - root->traverse(&scalarizer); - - return compiler->validateAST(root); -} - -} // namespace sh diff --git a/src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.cpp b/src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.cpp new file mode 100644 index 0000000..fb746f7 --- /dev/null +++ b/src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.cpp @@ -0,0 +1,378 @@ +// +// Copyright 2002 The ANGLE Project Authors. All rights reserved. +// 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 "compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.h" + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ +// Traverser that converts a vector or matrix constructor to one that only uses scalars. To support +// all the various places such a constructor could be found, a helper function is created for each +// such constructor. The helper function takes the constructor arguments and creates the object. +// +// Constructors that are transformed are: +// +// - vecN(scalar): translates to vecN(scalar, ..., scalar) +// - vecN(vec1, vec2, ...): translates to vecN(vec1.x, vec1.y, vec2.x, ...) +// - vecN(matrix): translates to vecN(matrix[0][0], matrix[0][1], ...) +// - matNxM(scalar): translates to matNxM(scalar, 0, ..., 0 +// 0, scalar, ..., 0 +// ... +// 0, 0, ..., scalar) +// - matNxM(vec1, vec2, ...): translates to matNxM(vec1.x, vec1.y, vec2.x, ...) +// - matNxM(matrixAxB): translates to matNxM(matrix[0][0], matrix[0][1], ..., 0 +// matrix[1][0], matrix[1][1], ..., 0 +// ... +// 0, 0, ..., 1) +// +class ScalarizeTraverser : public TIntermTraverser +{ + public: + ScalarizeTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable) + {} + + bool update(TCompiler *compiler, TIntermBlock *root); + + protected: + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + private: + bool shouldScalarize(TIntermTyped *node); + + // Create a helper function that takes the same arguments as the constructor it replaces. + const TFunction *createHelper(TIntermAggregate *node); + TIntermTyped *createHelperCall(TIntermAggregate *node, const TFunction *helper); + void addHelperDefinition(const TFunction *helper, TIntermBlock *body); + + // If given a constructor, convert it to a function call. Recursively processes constructor + // arguments. Otherwise, recursively visit the node. + TIntermTyped *createConstructor(TIntermTyped *node); + + void extractComponents(const TFunction *helper, + size_t componentCount, + TIntermSequence *componentsOut); + + void createConstructorVectorFromScalar(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut); + void createConstructorVectorFromMultiple(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut); + void createConstructorMatrixFromScalar(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut); + void createConstructorMatrixFromVectors(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut); + void createConstructorMatrixFromMatrix(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut); + + TIntermSequence mFunctionsToAdd; +}; + +bool ScalarizeTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (!shouldScalarize(node)) + { + return true; + } + + TIntermTyped *replacement = createConstructor(node); + if (replacement != node) + { + queueReplacement(replacement, OriginalNode::IS_DROPPED); + } + // createConstructor already visits children + return false; +} + +bool ScalarizeTraverser::shouldScalarize(TIntermTyped *typed) +{ + TIntermAggregate *node = typed->getAsAggregate(); + if (node == nullptr || node->getOp() != EOpConstruct) + { + return false; + } + + const TType &type = node->getType(); + const TIntermSequence &arguments = *node->getSequence(); + const TType &arg0Type = arguments[0]->getAsTyped()->getType(); + + const bool isSingleVectorCast = arguments.size() == 1 && type.isVector() && + arg0Type.isVector() && + type.getNominalSize() == arg0Type.getNominalSize(); + const bool isSingleMatrixCast = arguments.size() == 1 && type.isMatrix() && + arg0Type.isMatrix() && type.getCols() == arg0Type.getCols() && + type.getRows() == arg0Type.getRows(); + + // Skip non-vector non-matrix constructors, as well as trivial constructors. + if (type.isArray() || type.getStruct() != nullptr || type.isScalar() || isSingleVectorCast || + isSingleMatrixCast) + { + return false; + } + + return true; +} + +const TFunction *ScalarizeTraverser::createHelper(TIntermAggregate *node) +{ + TFunction *helper = new TFunction(mSymbolTable, kEmptyImmutableString, + SymbolType::AngleInternal, &node->getType(), true); + + const TIntermSequence &arguments = *node->getSequence(); + for (TIntermNode *arg : arguments) + { + TType *argType = new TType(arg->getAsTyped()->getType()); + argType->setQualifier(EvqParamIn); + + TVariable *argVar = + new TVariable(mSymbolTable, kEmptyImmutableString, argType, SymbolType::AngleInternal); + helper->addParameter(argVar); + } + + return helper; +} + +TIntermTyped *ScalarizeTraverser::createHelperCall(TIntermAggregate *node, const TFunction *helper) +{ + TIntermSequence callArgs; + + const TIntermSequence &arguments = *node->getSequence(); + for (TIntermNode *arg : arguments) + { + // Note: createConstructor makes sure the arg is visited even if not constructor. + callArgs.push_back(createConstructor(arg->getAsTyped())); + } + + return TIntermAggregate::CreateFunctionCall(*helper, &callArgs); +} + +void ScalarizeTraverser::addHelperDefinition(const TFunction *helper, TIntermBlock *body) +{ + mFunctionsToAdd.push_back( + new TIntermFunctionDefinition(new TIntermFunctionPrototype(helper), body)); +} + +TIntermTyped *ScalarizeTraverser::createConstructor(TIntermTyped *typed) +{ + if (!shouldScalarize(typed)) + { + typed->traverse(this); + return typed; + } + + TIntermAggregate *node = typed->getAsAggregate(); + const TType &type = node->getType(); + const TIntermSequence &arguments = *node->getSequence(); + const TType &arg0Type = arguments[0]->getAsTyped()->getType(); + + const TFunction *helper = createHelper(node); + TIntermSequence constructorArgs; + + if (type.isVector()) + { + if (arguments.size() == 1 && arg0Type.isScalar()) + { + createConstructorVectorFromScalar(node, helper, &constructorArgs); + } + createConstructorVectorFromMultiple(node, helper, &constructorArgs); + } + else + { + ASSERT(type.isMatrix()); + + if (arg0Type.isScalar() && arguments.size() == 1) + { + createConstructorMatrixFromScalar(node, helper, &constructorArgs); + } + if (arg0Type.isMatrix()) + { + createConstructorMatrixFromMatrix(node, helper, &constructorArgs); + } + createConstructorMatrixFromVectors(node, helper, &constructorArgs); + } + + TIntermBlock *body = new TIntermBlock; + body->appendStatement( + new TIntermBranch(EOpReturn, TIntermAggregate::CreateConstructor(type, &constructorArgs))); + addHelperDefinition(helper, body); + + return createHelperCall(node, helper); +} + +// Extract enough scalar arguments from the arguments of helper to produce enough arguments for the +// constructor call (given in componentCount). +void ScalarizeTraverser::extractComponents(const TFunction *helper, + size_t componentCount, + TIntermSequence *componentsOut) +{ + for (size_t argumentIndex = 0; + argumentIndex < helper->getParamCount() && componentsOut->size() < componentCount; + ++argumentIndex) + { + TIntermTyped *argument = new TIntermSymbol(helper->getParam(argumentIndex)); + const TType &argumentType = argument->getType(); + + if (argumentType.isScalar()) + { + // For scalar parameters, there's nothing to do + componentsOut->push_back(argument); + continue; + } + if (argumentType.isVector()) + { + // For vector parameters, take components out of the vector one by one. + for (uint8_t componentIndex = 0; componentIndex < argumentType.getNominalSize() && + componentsOut->size() < componentCount; + ++componentIndex) + { + componentsOut->push_back( + new TIntermSwizzle(argument->deepCopy(), {componentIndex})); + } + continue; + } + + ASSERT(argumentType.isMatrix()); + + // For matrix parameters, take components out of the matrix one by one in column-major + // order. + for (uint8_t columnIndex = 0; + columnIndex < argumentType.getCols() && componentsOut->size() < componentCount; + ++columnIndex) + { + TIntermTyped *col = new TIntermBinary(EOpIndexDirect, argument->deepCopy(), + CreateIndexNode(columnIndex)); + + for (uint8_t componentIndex = 0; + componentIndex < argumentType.getRows() && componentsOut->size() < componentCount; + ++componentIndex) + { + componentsOut->push_back(new TIntermSwizzle(col->deepCopy(), {componentIndex})); + } + } + } +} + +void ScalarizeTraverser::createConstructorVectorFromScalar(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut) +{ + ASSERT(helper->getParamCount() == 1); + TIntermTyped *scalar = new TIntermSymbol(helper->getParam(0)); + const TType &type = node->getType(); + + // Replicate the single scalar argument as many times as necessary. + for (size_t index = 0; index < type.getNominalSize(); ++index) + { + constructorArgsOut->push_back(scalar->deepCopy()); + } +} + +void ScalarizeTraverser::createConstructorVectorFromMultiple(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut) +{ + extractComponents(helper, node->getType().getNominalSize(), constructorArgsOut); +} + +void ScalarizeTraverser::createConstructorMatrixFromScalar(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut) +{ + ASSERT(helper->getParamCount() == 1); + TIntermTyped *scalar = new TIntermSymbol(helper->getParam(0)); + const TType &type = node->getType(); + + // Create the scalar over the diagonal. Every other element is 0. + for (uint8_t columnIndex = 0; columnIndex < type.getCols(); ++columnIndex) + { + for (uint8_t rowIndex = 0; rowIndex < type.getRows(); ++rowIndex) + { + if (columnIndex == rowIndex) + { + constructorArgsOut->push_back(scalar->deepCopy()); + } + else + { + ASSERT(type.getBasicType() == EbtFloat); + constructorArgsOut->push_back(CreateFloatNode(0, type.getPrecision())); + } + } + } +} + +void ScalarizeTraverser::createConstructorMatrixFromVectors(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut) +{ + const TType &type = node->getType(); + extractComponents(helper, type.getCols() * type.getRows(), constructorArgsOut); +} + +void ScalarizeTraverser::createConstructorMatrixFromMatrix(TIntermAggregate *node, + const TFunction *helper, + TIntermSequence *constructorArgsOut) +{ + ASSERT(helper->getParamCount() == 1); + TIntermTyped *matrix = new TIntermSymbol(helper->getParam(0)); + const TType &type = node->getType(); + + // The result is the identity matrix with the size of the result, superimposed by the input + for (uint8_t columnIndex = 0; columnIndex < type.getCols(); ++columnIndex) + { + for (uint8_t rowIndex = 0; rowIndex < type.getRows(); ++rowIndex) + { + if (columnIndex < matrix->getType().getCols() && rowIndex < matrix->getType().getRows()) + { + TIntermTyped *col = new TIntermBinary(EOpIndexDirect, matrix->deepCopy(), + CreateIndexNode(columnIndex)); + constructorArgsOut->push_back( + new TIntermSwizzle(col, {static_cast(rowIndex)})); + } + else + { + ASSERT(type.getBasicType() == EbtFloat); + constructorArgsOut->push_back( + CreateFloatNode(columnIndex == rowIndex ? 1.0f : 0.0f, type.getPrecision())); + } + } + } +} + +bool ScalarizeTraverser::update(TCompiler *compiler, TIntermBlock *root) +{ + // Insert any added function definitions at the tope of the block + root->insertChildNodes(0, mFunctionsToAdd); + + // Apply updates and validate + return updateTree(compiler, root); +} +} // namespace + +bool ScalarizeVecAndMatConstructorArgs(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable) +{ + ScalarizeTraverser scalarizer(symbolTable); + root->traverse(&scalarizer); + return scalarizer.update(compiler, root); +} +} // namespace sh diff --git a/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h b/src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.h similarity index 58% rename from src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h rename to src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.h index 617cbd7..4762a04 100644 --- a/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h +++ b/src/compiler/translator/tree_ops/gl/ScalarizeVecAndMatConstructorArgs.h @@ -8,11 +8,12 @@ // driver bugs around vector and matrix constructors. // -#ifndef COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ -#define COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ +#ifndef COMPILER_TRANSLATOR_TREEOPS_GL_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_GL_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ #include "GLSLANG/ShaderLang.h" #include "common/angleutils.h" +#include "common/debug.h" namespace sh { @@ -20,9 +21,21 @@ class TCompiler; class TIntermBlock; class TSymbolTable; +#ifdef ANGLE_ENABLE_GLSL [[nodiscard]] bool ScalarizeVecAndMatConstructorArgs(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable); +#else +[[nodiscard]] ANGLE_INLINE bool ScalarizeVecAndMatConstructorArgs(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable) +{ + UNREACHABLE(); + return false; +} +#endif + } // namespace sh -#endif // COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ +#endif // COMPILER_TRANSLATOR_TREEOPS_GL_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ + diff --git a/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp b/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp index 59241bc..be55891 100644 --- a/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp +++ b/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp @@ -17,33 +17,6 @@ namespace sh { -namespace -{ - -bool ContainsMatrixNode(const TIntermSequence &sequence) -{ - for (size_t ii = 0; ii < sequence.size(); ++ii) - { - TIntermTyped *node = sequence[ii]->getAsTyped(); - if (node && node->isMatrix()) - return true; - } - return false; -} - -bool ContainsVectorNode(const TIntermSequence &sequence) -{ - for (size_t ii = 0; ii < sequence.size(); ++ii) - { - TIntermTyped *node = sequence[ii]->getAsTyped(); - if (node && node->isVector()) - return true; - } - return false; -} - -} // anonymous namespace - IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {} // static @@ -147,20 +120,6 @@ bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parent } } } - if ((mMask & kScalarizedVecOrMatConstructor) != 0) - { - if (node->getOp() == EOpConstruct) - { - if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence()))) - { - return true; - } - else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence()))) - { - return true; - } - } - } return false; } diff --git a/src/compiler/translator/tree_util/IntermNodePatternMatcher.h b/src/compiler/translator/tree_util/IntermNodePatternMatcher.h index b8321b9..ceafd92 100644 --- a/src/compiler/translator/tree_util/IntermNodePatternMatcher.h +++ b/src/compiler/translator/tree_util/IntermNodePatternMatcher.h @@ -51,10 +51,6 @@ class IntermNodePatternMatcher // Matches array length() method. kArrayLengthMethod = 1u << 6u, - - // Matches a vector or matrix constructor whose arguments are scalarized by the - // scalarizeVecOrMatConstructorArguments workaround. - kScalarizedVecOrMatConstructor = 1u << 7u, }; IntermNodePatternMatcher(const unsigned int mask); diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp index a91f8b0..a866b25 100644 --- a/src/compiler/translator/util.cpp +++ b/src/compiler/translator/util.cpp @@ -282,6 +282,9 @@ GLenum GLVariableType(const TType &type) return kBoolGLType[type.getNominalSize() - 1]; + case EbtYuvCscStandardEXT: + return GL_UNSIGNED_INT; + case EbtSampler2D: return GL_SAMPLER_2D; case EbtSampler3D: diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp index 970f61b..86b496e 100644 --- a/src/libANGLE/Display.cpp +++ b/src/libANGLE/Display.cpp @@ -2240,9 +2240,6 @@ void Display::initializeFrontendFeatures() ANGLE_FEATURE_CONDITION((&mFrontendFeatures), loseContextOnOutOfMemory, true); ANGLE_FEATURE_CONDITION((&mFrontendFeatures), allowCompressedFormats, true); - // No longer enable this on any Impl - crbug.com/1165751 - ANGLE_FEATURE_CONDITION((&mFrontendFeatures), scalarizeVecAndMatConstructorArgs, false); - // Togglable until work on the extension is complete - anglebug.com/7279. ANGLE_FEATURE_CONDITION(&mFrontendFeatures, emulatePixelLocalStorage, true); diff --git a/src/libANGLE/Shader.cpp b/src/libANGLE/Shader.cpp index 485eb80..b3e46f0 100644 --- a/src/libANGLE/Shader.cpp +++ b/src/libANGLE/Shader.cpp @@ -427,11 +427,6 @@ void Shader::compile(const Context *context) options.validateLoopIndexing = true; } - if (context->getFrontendFeatures().scalarizeVecAndMatConstructorArgs.enabled) - { - options.scalarizeVecAndMatConstructorArgs = true; - } - if (context->getFrontendFeatures().forceInitShaderVariables.enabled) { options.initOutputVariables = true; diff --git a/src/libANGLE/renderer/gl/BufferGL.cpp b/src/libANGLE/renderer/gl/BufferGL.cpp index c99fd5d..9651838 100644 --- a/src/libANGLE/renderer/gl/BufferGL.cpp +++ b/src/libANGLE/renderer/gl/BufferGL.cpp @@ -296,6 +296,11 @@ angle::Result BufferGL::getIndexRange(const gl::Context *context, return angle::Result::Continue; } +size_t BufferGL::getBufferSize() const +{ + return mBufferSize; +} + GLuint BufferGL::getBufferID() const { return mBufferID; diff --git a/src/libANGLE/renderer/gl/BufferGL.h b/src/libANGLE/renderer/gl/BufferGL.h index 7b57594..fe9138e 100644 --- a/src/libANGLE/renderer/gl/BufferGL.h +++ b/src/libANGLE/renderer/gl/BufferGL.h @@ -56,6 +56,7 @@ class BufferGL : public BufferImpl bool primitiveRestartEnabled, gl::IndexRange *outRange) override; + size_t getBufferSize() const; GLuint getBufferID() const; private: diff --git a/src/libANGLE/renderer/gl/ShaderGL.cpp b/src/libANGLE/renderer/gl/ShaderGL.cpp index a72b064..fcad3f5 100644 --- a/src/libANGLE/renderer/gl/ShaderGL.cpp +++ b/src/libANGLE/renderer/gl/ShaderGL.cpp @@ -381,6 +381,11 @@ std::shared_ptr ShaderGL::compile(const gl::Context *conte options->emulateClipDistanceState = true; } + if (features.scalarizeVecAndMatConstructorArgs.enabled) + { + options->scalarizeVecAndMatConstructorArgs = true; + } + if (mRenderer->getNativeExtensions().shaderPixelLocalStorageANGLE) { options->pls = mRenderer->getNativePixelLocalStorageOptions(); diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp index dc981de..106449e 100644 --- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp +++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp @@ -489,6 +489,15 @@ angle::Result VertexArrayGL::streamAttributes( // The workaround is only for latest Mac Intel so glMapBufferRange should be // supported ASSERT(CanMapBufferForRead(functions)); + // Validate if there is OOB access of the input buffer. + angle::CheckedNumeric inputRequiredSize; + inputRequiredSize = copySize; + inputRequiredSize += static_cast(binding.getOffset()); + ANGLE_CHECK(GetImplAs(context), + inputRequiredSize.IsValid() && inputRequiredSize.ValueOrDie() <= + bindingBufferPointer->getSize(), + "Failed to map buffer range of the attribute buffer.", + GL_OUT_OF_MEMORY); uint8_t *inputBufferPointer = MapBufferRangeWithFallback( functions, GL_ARRAY_BUFFER, binding.getOffset(), copySize, GL_MAP_READ_BIT); ASSERT(inputBufferPointer); @@ -646,6 +655,7 @@ angle::Result VertexArrayGL::updateAttribEnabled(const gl::Context *context, siz angle::Result VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex) { + const angle::FeaturesGL &features = GetFeaturesGL(context); const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex); @@ -687,8 +697,16 @@ angle::Result VertexArrayGL::updateAttribPointer(const gl::Context *context, siz // is not NULL. StateManagerGL *stateManager = GetStateManagerGL(context); - GLuint bufferId = GetNativeBufferID(arrayBuffer); + BufferGL *bufferGL = GetImplAs(arrayBuffer); + GLuint bufferId = bufferGL->getBufferID(); stateManager->bindBuffer(gl::BufferBinding::Array, bufferId); + if (features.ensureNonEmptyBufferIsBoundForDraw.enabled && bufferGL->getBufferSize() == 0) + { + constexpr uint32_t data = 0; + ANGLE_TRY(bufferGL->setData(context, gl::BufferBinding::Array, &data, sizeof(data), + gl::BufferUsage::StaticDraw)); + ASSERT(bufferGL->getBufferSize() > 0); + } ANGLE_TRY(callVertexAttribPointer(context, static_cast(attribIndex), attrib, binding.getStride(), binding.getOffset())); diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp index e8056b8..71c7eb6 100644 --- a/src/libANGLE/renderer/gl/renderergl_utils.cpp +++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp @@ -2543,6 +2543,12 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature // https://crbug.com/1356053 ANGLE_FEATURE_CONDITION(features, bindFramebufferForTimerQueries, IsMali(functions)); + + // http://crbug.com/1420130 + ANGLE_FEATURE_CONDITION(features, scalarizeVecAndMatConstructorArgs, IsMali(functions)); + + // http://crbug.com/1456243 + ANGLE_FEATURE_CONDITION(features, ensureNonEmptyBufferIsBoundForDraw, IsApple() || IsAndroid()); } void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features) diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp index 2e07deb..93a1092 100644 --- a/src/libANGLE/renderer/vulkan/BufferVk.cpp +++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp @@ -305,7 +305,7 @@ void BufferVk::release(ContextVk *contextVk) RendererVk *renderer = contextVk->getRenderer(); if (mBuffer.valid()) { - mBuffer.releaseBufferAndDescriptorSetCache(contextVk); + mBuffer.releaseBufferAndDescriptorSetCache(renderer); } if (mStagingBuffer.valid()) { @@ -623,7 +623,7 @@ angle::Result BufferVk::ghostMappedBuffer(ContextVk *contextVk, memcpy(dstMapPtr, srcMapPtr, static_cast(mState.getSize())); } - src.releaseBufferAndDescriptorSetCache(contextVk); + src.releaseBufferAndDescriptorSetCache(contextVk->getRenderer()); // Return the already mapped pointer with the offset adjustment to avoid the call to unmap(). *mapPtr = dstMapPtr + offset; @@ -1029,7 +1029,7 @@ angle::Result BufferVk::acquireAndUpdate(ContextVk *contextVk, if (prevBuffer.valid()) { - prevBuffer.releaseBufferAndDescriptorSetCache(contextVk); + prevBuffer.releaseBufferAndDescriptorSetCache(contextVk->getRenderer()); } return angle::Result::Continue; @@ -1151,7 +1151,7 @@ angle::Result BufferVk::acquireBufferHelper(ContextVk *contextVk, if (mBuffer.valid()) { - mBuffer.releaseBufferAndDescriptorSetCache(contextVk); + mBuffer.releaseBufferAndDescriptorSetCache(renderer); } // Allocate the buffer directly diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp index 9d1fa2f..24a5acb 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp @@ -3801,6 +3801,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk, ANGLE_FEATURE_CONDITION(&mFeatures, clampPointSize, isNvidia && nvidiaVersion.major < uint32_t(IsWindows() ? 430 : 421)); + // Affecting Linux/Intel (unknown range). + ANGLE_FEATURE_CONDITION(&mFeatures, wrapSwitchInIfTrue, isIntel && IsLinux()); + ANGLE_FEATURE_CONDITION(&mFeatures, supportsDepthClipEnable, mDepthClipEnableFeatures.depthClipEnable == VK_TRUE); diff --git a/src/libANGLE/renderer/vulkan/Suballocation.h b/src/libANGLE/renderer/vulkan/Suballocation.h index d25481b..276f6b4 100644 --- a/src/libANGLE/renderer/vulkan/Suballocation.h +++ b/src/libANGLE/renderer/vulkan/Suballocation.h @@ -86,6 +86,13 @@ class BufferBlock final : angle::NonCopyable { mDescriptorSetCacheManager.addKey(sharedCacheKey); } + void releaseAllCachedDescriptorSetCacheKeys(RendererVk *renderer) + { + if (!mDescriptorSetCacheManager.empty()) + { + mDescriptorSetCacheManager.releaseKeys(renderer); + } + } private: mutable std::mutex mVirtualBlockMutex; diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp index c56ea84..2481e58 100644 --- a/src/libANGLE/renderer/vulkan/TextureVk.cpp +++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp @@ -1643,7 +1643,7 @@ void TextureVk::releaseAndDeleteImageAndViews(ContextVk *contextVk) onStateChange(angle::SubjectMessage::SubjectChanged); } mRedefinedLevels.reset(); - mDescriptorSetCacheManager.releaseKeys(contextVk); + mDescriptorSetCacheManager.releaseKeys(contextVk->getRenderer()); } void TextureVk::initImageUsageFlags(ContextVk *contextVk, angle::FormatID actualFormatID) @@ -2877,7 +2877,7 @@ angle::Result TextureVk::syncState(const gl::Context *context, mBufferViews.release(contextVk); mBufferViews.init(renderer, offset, size); - mDescriptorSetCacheManager.releaseKeys(contextVk); + mDescriptorSetCacheManager.releaseKeys(renderer); return angle::Result::Continue; } @@ -3320,7 +3320,7 @@ void TextureVk::releaseImageViews(ContextVk *contextVk) { RendererVk *renderer = contextVk->getRenderer(); - mDescriptorSetCacheManager.releaseKeys(contextVk); + mDescriptorSetCacheManager.releaseKeys(renderer); if (mImage == nullptr) { diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp index f750428..ae86b29 100644 --- a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp +++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp @@ -2589,11 +2589,19 @@ void ReleaseCachedObject(ContextVk *contextVk, const FramebufferDesc &desc) { contextVk->getShareGroup()->getFramebufferCache().erase(contextVk, desc); } +void ReleaseCachedObject(RendererVk *renderer, const FramebufferDesc &desc) +{ + UNREACHABLE(); +} void ReleaseCachedObject(ContextVk *contextVk, const DescriptorSetDescAndPool &descAndPool) +{ + UNREACHABLE(); +} +void ReleaseCachedObject(RendererVk *renderer, const DescriptorSetDescAndPool &descAndPool) { ASSERT(descAndPool.mPool != nullptr); - descAndPool.mPool->releaseCachedDescriptorSet(contextVk, descAndPool.mDesc); + descAndPool.mPool->releaseCachedDescriptorSet(renderer, descAndPool.mDesc); } void DestroyCachedObject(RendererVk *renderer, const FramebufferDesc &desc) @@ -6260,6 +6268,22 @@ void SharedCacheKeyManager::releaseKeys(ContextVk *contextVk) mSharedCacheKeys.clear(); } +template +void SharedCacheKeyManager::releaseKeys(RendererVk *renderer) +{ + for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys) + { + if (*sharedCacheKey.get() != nullptr) + { + // Immediate destroy the cached object and the key itself when first releaseKeys call is + // made + ReleaseCachedObject(renderer, *(*sharedCacheKey.get())); + *sharedCacheKey.get() = nullptr; + } + } + mSharedCacheKeys.clear(); +} + template void SharedCacheKeyManager::destroyKeys(RendererVk *renderer) { diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.h b/src/libANGLE/renderer/vulkan/vk_cache_utils.h index 8c9d452..f85459a 100644 --- a/src/libANGLE/renderer/vulkan/vk_cache_utils.h +++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.h @@ -1932,6 +1932,7 @@ class SharedCacheKeyManager void addKey(const SharedCacheKeyT &key); // Iterate over the descriptor array and release the descriptor and cache. void releaseKeys(ContextVk *contextVk); + void releaseKeys(RendererVk *rendererVk); // Iterate over the descriptor array and destroy the descriptor and cache. void destroyKeys(RendererVk *renderer); void clear(); diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp index 9088e09..8bc027d 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp +++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp @@ -3798,7 +3798,7 @@ angle::Result DynamicDescriptorPool::allocateNewPool(Context *context) return mDescriptorPools[mCurrentPoolIndex]->get().init(context, mPoolSizes, mMaxSetsPerPool); } -void DynamicDescriptorPool::releaseCachedDescriptorSet(ContextVk *contextVk, +void DynamicDescriptorPool::releaseCachedDescriptorSet(RendererVk *renderer, const DescriptorSetDesc &desc) { VkDescriptorSet descriptorSet; @@ -3812,7 +3812,7 @@ void DynamicDescriptorPool::releaseCachedDescriptorSet(ContextVk *contextVk, // Wrap it with helper object so that it can be GPU tracked and add it to resource list. DescriptorSetHelper descriptorSetHelper(poolOut->get().getResourceUse(), descriptorSet); poolOut->get().addGarbage(std::move(descriptorSetHelper)); - checkAndReleaseUnusedPool(contextVk->getRenderer(), poolOut); + checkAndReleaseUnusedPool(renderer, poolOut); } } @@ -5016,6 +5016,12 @@ void BufferHelper::release(RendererVk *renderer) if (mSuballocation.valid()) { + if (!mSuballocation.isSuballocated()) + { + // Destroy cacheKeys now to avoid getting into situation that having to destroy + // descriptorSet from garbage collection thread. + mSuballocation.getBufferBlock()->releaseAllCachedDescriptorSetCacheKeys(renderer); + } renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation), std::move(mBufferForVertexArray)); } @@ -5024,17 +5030,15 @@ void BufferHelper::release(RendererVk *renderer) ASSERT(!mBufferForVertexArray.valid()); } -void BufferHelper::releaseBufferAndDescriptorSetCache(ContextVk *contextVk) +void BufferHelper::releaseBufferAndDescriptorSetCache(RendererVk *renderer) { - RendererVk *renderer = contextVk->getRenderer(); - if (renderer->hasResourceUseFinished(getResourceUse())) { mDescriptorSetCacheManager.destroyKeys(renderer); } else { - mDescriptorSetCacheManager.releaseKeys(contextVk); + mDescriptorSetCacheManager.releaseKeys(renderer); } release(renderer); diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h index d2405b6..962dfe8 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.h +++ b/src/libANGLE/renderer/vulkan/vk_helpers.h @@ -252,7 +252,7 @@ class DynamicDescriptorPool final : angle::NonCopyable VkDescriptorSet *descriptorSetOut, SharedDescriptorSetCacheKey *sharedCacheKeyOut); - void releaseCachedDescriptorSet(ContextVk *contextVk, const DescriptorSetDesc &desc); + void releaseCachedDescriptorSet(RendererVk *renderer, const DescriptorSetDesc &desc); void destroyCachedDescriptorSet(RendererVk *renderer, const DescriptorSetDesc &desc); template @@ -777,7 +777,7 @@ class BufferHelper : public ReadWriteResource void destroy(RendererVk *renderer); void release(RendererVk *renderer); - void releaseBufferAndDescriptorSetCache(ContextVk *contextVk); + void releaseBufferAndDescriptorSetCache(RendererVk *renderer); BufferSerial getBufferSerial() const { return mSerial; } BufferSerial getBlockSerial() const diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt index 93a4752..46dbbc0 100644 --- a/src/tests/angle_end2end_tests_expectations.txt +++ b/src/tests/angle_end2end_tests_expectations.txt @@ -235,8 +235,6 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* = 6570 MAC INTEL OPENGL : WebGLCompatibilityTest.RG32FTextures/* = SKIP 6570 MAC INTEL OPENGL : WebGLCompatibilityTest.RGB32FTextures/* = SKIP 6603 MAC OPENGL : ProgramBinaryES3Test.SaveAndLoadDetachedShaders/* = SKIP -8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP -8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP 6643 MAC AMD OPENGL : TransformFeedbackTest.TransformFeedbackQueryPausedDrawThenResume/* = SKIP 6643 MAC AMD OPENGL : TransformFeedbackTest.TransformFeedbackPausedDrawThenResume/* = SKIP 6738 MAC AMD OPENGL : Texture3DTestES3.PixelUnpackStateTex* = SKIP @@ -415,6 +413,7 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* = 7316 WIN D3D11 : StateChangeTestES3.StencilTestAndFunc/* = SKIP 7329 WIN D3D11 : StateChangeTestES3.PrimitiveRestart/* = SKIP 8100 WIN D3D11 : WebGL2GLSLTest.InitOutputParams/* = SKIP +1456243 WIN D3D11 : WebGL2CompatibilityTest.DrawWithZeroSizedBuffer/* = SKIP // Android 6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP @@ -519,6 +518,7 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* = 7703 PIXEL4ORXL GLES : FramebufferFetchES31.ProgramPipeline* = SKIP 7703 PIXEL4ORXL GLES : FramebufferFetchES31.DrawNonFetchDrawFetchInStorageBuffer* = SKIP 2046 PIXEL4ORXL GLES : WebGL2GLSLTest.InitOutputParams/* = SKIP +8250 PIXEL4ORXL GLES : GLSLTest_ES3.ComplexConstructor/* = SKIP 3423 PIXEL4ORXL VULKAN : ClearTestES3.MaskedClearBufferBug/* = SKIP 3423 PIXEL4ORXL VULKAN : DrawBuffersWebGL2Test.TwoProgramsWithDifferentOutputsAndClear/* = SKIP @@ -1054,6 +1054,10 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* = 7389 SWIFTSHADER : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP 7389 MAC OPENGL : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP +8437 MAC OPENGL : GLSLTest_ES3.LotsOfFieldsInStruct/* = SKIP +8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP +8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP + // GL, GLES run into issues with cleanup 7495 WIN OpenGL : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP 7495 WIN GLES : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP diff --git a/src/tests/angle_unittests.gni b/src/tests/angle_unittests.gni index 2280888..ad2b224 100644 --- a/src/tests/angle_unittests.gni +++ b/src/tests/angle_unittests.gni @@ -133,7 +133,6 @@ angle_unittests_compiler_tests_sources = [ "compiler_tests/RemoveUnreferencedVariables_test.cpp", "compiler_tests/SamplerMultisample_test.cpp", "compiler_tests/SamplerVideoWEBGL_test.cpp", - "compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp", "compiler_tests/ShCompile_test.cpp", "compiler_tests/ShaderImage_test.cpp", "compiler_tests/ShaderValidation_test.cpp", diff --git a/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp b/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp deleted file mode 100644 index 70ce712..0000000 --- a/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// -// 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. -// -// ScalarizeVecAndMatConstructorArgs_test.cpp: -// Tests for scalarizing vector and matrix constructor args. -// - -#include "GLSLANG/ShaderLang.h" -#include "angle_gl.h" -#include "gtest/gtest.h" -#include "tests/test_utils/compiler_test.h" - -using namespace sh; - -namespace -{ - -class ScalarizeVecAndMatConstructorArgsTest : public MatchOutputCodeTest -{ - public: - ScalarizeVecAndMatConstructorArgsTest() - : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT) - { - ShCompileOptions defaultCompileOptions = {}; - defaultCompileOptions.scalarizeVecAndMatConstructorArgs = true; - setDefaultCompileOptions(defaultCompileOptions); - } -}; - -// Verifies scalarizing matrix inside a vector constructor. -TEST_F(ScalarizeVecAndMatConstructorArgsTest, MatrixInVectorConstructor) -{ - const std::string shaderString = - R"( - precision mediump float; - - uniform mat2 umat2; - - void main() - { - gl_FragColor = vec4(umat2); - })"; - compile(shaderString); - - std::vector expectedStrings = { - "main()", " = _uumat2", "gl_FragColor = vec4(", "[0][0],", "[0][1],", "[1][0],", "[1][1])"}; - - EXPECT_TRUE(foundInCodeInOrder(expectedStrings)); -} - -// Verifies scalarizing a vector insized a matrix constructor. -TEST_F(ScalarizeVecAndMatConstructorArgsTest, VectorInMatrixConstructor) -{ - const std::string shaderString = - R"( - precision mediump float; - - uniform vec2 uvec2; - - void main() - { - mat2 m = mat2(uvec2, uvec2); - gl_FragColor = vec4(m * uvec2, m * uvec2); - })"; - compile(shaderString); - - std::vector expectedStrings = { - "main()", " = _uuvec2", "mat2(", "[0],", "[1],", "[0],", "[1])", "gl_FragColor = vec4("}; - - EXPECT_TRUE(foundInCodeInOrder(expectedStrings)); -} - -// Verifies that scalarizing vector and matrix constructor args inside a sequence operator preserves -// correct order of operations. -TEST_F(ScalarizeVecAndMatConstructorArgsTest, SequenceOperator) -{ - const std::string shaderString = - R"( - precision mediump float; - - uniform vec2 u; - - void main() - { - vec2 v = u; - mat2 m = (v[0] += 1.0, mat2(v, v[1], -v[0])); - gl_FragColor = vec4(m[0], m[1]); - })"; - compile(shaderString); - - std::vector expectedStrings = {"_uv[0] += ", "-_uv[0]"}; - - EXPECT_TRUE(foundInCodeInOrder(expectedStrings)); -} - -// Verifies that scalarizing vector and matrix constructor args inside multiple declarations -// preserves the correct order of operations. -TEST_F(ScalarizeVecAndMatConstructorArgsTest, MultiDeclaration) -{ - const std::string shaderString = - R"( - precision mediump float; - - uniform vec2 u; - - void main() - { - vec2 v = vec2(u[0]), - w = mat2(v, v) * u; - gl_FragColor = vec4(v, w); - })"; - compile(shaderString); - - std::vector expectedStrings = {"vec2(_uu[0])", "mat2("}; - - EXPECT_TRUE(foundInCodeInOrder(expectedStrings)); -} - -// Verifies that constructors without precision don't cause issues. -TEST_F(ScalarizeVecAndMatConstructorArgsTest, ConstructorWithoutPrecision) -{ - const std::string shaderString = - R"( - precision mediump float; - - uniform float u; - - void main() - { - mat4 m = mat4(u); - mat2(0, bvec3(m)); - })"; - compile(shaderString); -} - -} // anonymous namespace diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp index a8df82b..051fed8 100644 --- a/src/tests/gl_tests/GLSLTest.cpp +++ b/src/tests/gl_tests/GLSLTest.cpp @@ -8406,7 +8406,7 @@ TEST_P(GLSLTest_ES3, ArrayLengthInVectorConstructor) const char kVS[] = R"(#version 300 es precision highp float; flat out uvec4 v; - + int[1] f0() { return int[1](1); @@ -8414,19 +8414,19 @@ int[1] f0() void main() { v = uvec4(vec4(f0().length())); - + gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0); gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0); gl_Position.zw = vec2(0, 1); })"; - + const char kFS[] = R"(#version 300 es precision highp float; flat in uvec4 v; out vec4 color; - + bool isEq(uint a, float b) { return abs(float(a) - b) < 0.01; } - + void main() { if (isEq(v[0], 1.) && @@ -8441,20 +8441,20 @@ void main() color = vec4(1, 0, 0, 1); } })"; - + ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } - + // Test that array length inside vector constructor works in complex expression. TEST_P(GLSLTest_ES3, ArrayLengthInVectorConstructorComplex) { const char kVS[] = R"(#version 300 es precision highp float; out vec4 v; - + int[1] f0() { return int[1](1); @@ -8462,20 +8462,19 @@ int[1] f0() void main() { v = vec4(float(uint(f0().length()) + 1u) / 4.); - + gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0); gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0); gl_Position.zw = vec2(0, 1); })"; - + const char kFS[] = R"(#version 300 es precision highp float; in vec4 v; out vec4 color; - - + bool isEq(float a, float b) { return abs(float(a) - b) < 0.01; } - + void main() { if (isEq(v[0], 0.5) && @@ -8490,19 +8489,20 @@ void main() color = vec4(1, 0, 0, 1); } })"; - + ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } - + // Test that array length inside matrix constructor works. TEST_P(GLSLTest_ES3, ArrayLengthInMatrixConstructor) { const char kVS[] = R"(#version 300 es precision highp float; out mat2x2 v; + int[1] f0() { return int[1](1); @@ -8510,19 +8510,19 @@ int[1] f0() void main() { v = mat2x2(f0().length()); - + gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0); gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0); gl_Position.zw = vec2(0, 1); })"; - + const char kFS[] = R"(#version 300 es precision highp float; in mat2x2 v; out vec4 color; - + bool isEq(float a, float b) { return abs(a - b) < 0.01; } - + void main() { if (isEq(v[0][0], 1.) && @@ -8537,20 +8537,20 @@ void main() color = vec4(1, 0, 0, 1); } })"; - + ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } - + // Test that array length inside vector constructor inside matrix constructor works. TEST_P(GLSLTest_ES3, ArrayLengthInVectorInMatrixConstructor) { const char kVS[] = R"(#version 300 es precision highp float; out mat2x2 v; - + int[1] f0() { return int[1](1); @@ -8558,19 +8558,19 @@ int[1] f0() void main() { v = mat2x2(vec2(f0().length()), f0().length(), 0); - + gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0); gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0); gl_Position.zw = vec2(0, 1); })"; - + const char kFS[] = R"(#version 300 es precision highp float; in mat2x2 v; out vec4 color; - + bool isEq(float a, float b) { return abs(a - b) < 0.01; } - + void main() { if (isEq(v[0][0], 1.) && @@ -8585,7 +8585,7 @@ void main() color = vec4(1, 0, 0, 1); } })"; - + ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -14653,6 +14653,182 @@ void main() glDeleteShader(shader); } +// Test constructors without precision +TEST_P(GLSLTest, ConstructFromBoolVector) +{ + constexpr char kFS[] = R"(precision mediump float; +uniform float u; +void main() +{ + mat4 m = mat4(u); + mat2(0, bvec3(m)); + gl_FragColor = vec4(m); +})"; + + GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS); + EXPECT_NE(0u, shader); + glDeleteShader(shader); +} + +// Test constructing vector from matrix +TEST_P(GLSLTest, VectorConstructorFromMatrix) +{ + constexpr char kFS[] = R"(precision mediump float; +uniform mat2 umat2; +void main() +{ + gl_FragColor = vec4(umat2); +})"; + + GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS); + EXPECT_NE(0u, shader); + glDeleteShader(shader); +} + +// Test constructing matrix from vectors +TEST_P(GLSLTest, MatrixConstructorFromVectors) +{ + constexpr char kFS[] = R"(precision mediump float; +uniform vec2 uvec2; +void main() +{ + mat2 m = mat2(uvec2, uvec2.yx); + gl_FragColor = vec4(m * uvec2, uvec2); +})"; + + ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS); + glUseProgram(program); + + GLint uloc = glGetUniformLocation(program, "uvec2"); + ASSERT_NE(uloc, -1); + glUniform2f(uloc, 0.5, 0.8); + + drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); + EXPECT_GL_NO_ERROR(); + + EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(227, 204, 127, 204), 1); +} + +// Test that constructing vector and matrix inside multiple declarations preserves the correct order +// of operations. +TEST_P(GLSLTest, ConstructorinSequenceOperator) +{ + constexpr char kFS[] = R"(precision mediump float; +uniform vec2 u; +void main() +{ + vec2 v = u; + mat2 m = (v[0] += 1.0, mat2(v, v[1], -v[0])); + gl_FragColor = vec4(m[0], m[1]); +})"; + + ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS); + glUseProgram(program); + + GLint uloc = glGetUniformLocation(program, "u"); + ASSERT_NE(uloc, -1); + glUniform2f(uloc, -0.5, 1.0); + + drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); + EXPECT_GL_NO_ERROR(); + + EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(127, 255, 255, 0), 1); +} + +// Test that constructing vectors inside multiple declarations preserves the correct order +// of operations. +TEST_P(GLSLTest, VectorConstructorsInMultiDeclaration) +{ + constexpr char kFS[] = R"(precision mediump float; +uniform vec2 u; +void main() +{ + vec2 v = vec2(u[0]), + w = mat2(v, v) * u; + gl_FragColor = vec4(v, w); +})"; + + ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS); + glUseProgram(program); + + GLint uloc = glGetUniformLocation(program, "u"); + ASSERT_NE(uloc, -1); + glUniform2f(uloc, 0.5, 0.8); + + drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); + EXPECT_GL_NO_ERROR(); + + EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(127, 127, 166, 166), 1); +} + +// Test complex constructor usage. +TEST_P(GLSLTest_ES3, ComplexConstructor) +{ + constexpr char kFS[] = R"(#version 300 es +precision mediump float; +uniform vec2 u; // = vec2(0.5, 0.8) +uniform vec2 v; // = vec2(-0.2, 1.0) + +out vec4 color; + +bool f(mat2 m) +{ + return m[0][0] > 0.; +} + +bool isEqual(float a, float b) +{ + return abs(a - b) < 0.01; +} + +void main() +{ + int shouldRemainZero = 0; + + // Test side effects inside constructor args after short-circuit + if (u.x < 0. && f(mat2(shouldRemainZero += 1, u, v))) + { + shouldRemainZero += 2; + } + + int shouldBecomeFive = 0; + + // Test directly nested constructors + mat4x3 m = mat4x3(mat2(shouldBecomeFive += 5, v, u)); + + // Test indirectly nested constructors + mat2 m2 = mat2(f(mat2(u, v)), f(mat2(v, u)), f(mat2(f(mat2(1.)))), -1.); + + // Verify + bool sideEffectsOk = shouldRemainZero == 0 && shouldBecomeFive == 5; + + bool mOk = isEqual(m[0][0], 5.) && isEqual(m[0][1], -0.2) && isEqual(m[0][2], 0.) && + isEqual(m[1][0], 1.) && isEqual(m[1][1], 0.5) && isEqual(m[1][2], 0.) && + isEqual(m[2][0], 0.) && isEqual(m[2][1], 0.) && isEqual(m[2][2], 1.) && + isEqual(m[3][0], 0.) && isEqual(m[3][1], 0.) && isEqual(m[3][2], 0.); + + bool m2Ok = isEqual(m2[0][0], 1.) && isEqual(m2[0][1], 0.) && + isEqual(m2[1][0], 1.) && isEqual(m2[1][1], -1.); + + color = vec4(sideEffectsOk ? 1 : 0, mOk ? 1 : 0, m2Ok ? 1 : 0, 1); +})"; + + ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); + glUseProgram(program); + + GLint uloc = glGetUniformLocation(program, "u"); + GLint vloc = glGetUniformLocation(program, "v"); + ASSERT_NE(uloc, -1); + ASSERT_NE(vloc, -1); + glUniform2f(uloc, 0.5, 0.8); + glUniform2f(vloc, -0.2, 1.0); + + drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f); + EXPECT_GL_NO_ERROR(); + + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); +} + // Test that scalar(nonScalar) constructors work. TEST_P(GLSLTest_ES3, ScalarConstructor) { @@ -18098,11 +18274,11 @@ out vec4 color; void main() { color = vec4(f(a), 0.0, 0.0, 1.0); })"; - + GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS); EXPECT_EQ(0u, shader); } - + // Make sure the shader in LargeInterfaceBlockArrayPassedToFunction works if the large local is // avoided. TEST_P(GLSLTest_ES3, LargeInterfaceBlockArray) @@ -18110,7 +18286,7 @@ TEST_P(GLSLTest_ES3, LargeInterfaceBlockArray) int maxUniformBlockSize = 0; glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize); ANGLE_SKIP_TEST_IF(maxUniformBlockSize < 16384 * 4); - + constexpr char kFS[] = R"(#version 300 es precision highp float; uniform Large { float a[16384]; }; @@ -18118,10 +18294,10 @@ out vec4 color; void main() { color = vec4(a[0], 0.0, 0.0, 1.0); })"; - + ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); } - + // Similar to LargeInterfaceBlockArrayPassedToFunction, but the array is nested in a struct. TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArrayPassedToFunction) { @@ -18138,11 +18314,11 @@ out vec4 color; void main() { color = vec4(f(s.a), 0.0, 0.0, 1.0); })"; - + GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS); EXPECT_EQ(0u, shader); } - + // Make sure the shader in LargeInterfaceBlockNestedArrayPassedToFunction works if the large local // is avoided. TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArray) @@ -18150,7 +18326,7 @@ TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArray) int maxUniformBlockSize = 0; glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize); ANGLE_SKIP_TEST_IF(maxUniformBlockSize < 16384 * 4); - + constexpr char kFS[] = R"(#version 300 es precision highp float; struct S { float a[16384]; }; @@ -18159,10 +18335,10 @@ out vec4 color; void main() { color = vec4(s.a[0], 0.0, 0.0, 1.0); })"; - + ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); } - + // Similar to LargeInterfaceBlockArrayPassedToFunction, but the large array is copied to a local // variable instead. TEST_P(GLSLTest_ES3, LargeInterfaceBlockArrayCopiedToLocal) @@ -18175,11 +18351,11 @@ void main() { float b[65536] = a; color = vec4(b[0], 0.0, 0.0, 1.0); })"; - + GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS); EXPECT_EQ(0u, shader); } - + // Similar to LargeInterfaceBlockArrayCopiedToLocal, but the array is nested in a struct TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArrayCopiedToLocal) { @@ -18192,11 +18368,11 @@ void main() { S s2 = s; color = vec4(s2.a[0], 0.0, 0.0, 1.0); })"; - + GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS); EXPECT_EQ(0u, shader); } - + // Test that too large varyings are rejected. TEST_P(GLSLTest_ES3, LargeArrayVarying) { @@ -18207,7 +18383,7 @@ out vec4 color; void main() { color = vec4(a[0], 0.0, 0.0, 1.0); })"; - + GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS); EXPECT_EQ(0u, shader); } diff --git a/src/tests/gl_tests/TransformFeedbackTest.cpp b/src/tests/gl_tests/TransformFeedbackTest.cpp index ea3eeea..b05fddc 100644 --- a/src/tests/gl_tests/TransformFeedbackTest.cpp +++ b/src/tests/gl_tests/TransformFeedbackTest.cpp @@ -4392,6 +4392,51 @@ TEST_P(TransformFeedbackTest, RenderOnceChangeXfbBufferRenderAgain) glEndTransformFeedback(); } +// Test bufferData call and transform feedback. +TEST_P(TransformFeedbackTest, BufferDataAndTransformFeedback) +{ + const char kVS[] = R"(#version 300 es +flat out highp int var; +void main() { +var = 1; +})"; + + const char kFS[] = R"(#version 300 es +flat in highp int var; +out highp int color; +void main() { +color = var; +})"; + + ANGLE_GL_PROGRAM(program, kVS, kFS); + + GLTexture texture; + glBindTexture(GL_TEXTURE_2D, texture); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, 1, 1); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); + + constexpr int kClearColor[] = {123, 0, 0, 0}; + glClearBufferiv(GL_COLOR, 0, kClearColor); + glDrawArrays(GL_POINTS, 0, 1); + + const char *kVarying = "var"; + glTransformFeedbackVaryings(program, 1, &kVarying, GL_INTERLEAVED_ATTRIBS); + glLinkProgram(program); + ASSERT_GL_NO_ERROR(); + + GLBuffer buffer; + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer); + glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 0x7ffc * 10000, nullptr, GL_DYNAMIC_READ); + glBeginTransformFeedback(GL_POINTS); + glDrawArrays(GL_POINTS, 0, 1); + glEndTransformFeedback(); + glFlush(); +} + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTest); ANGLE_INSTANTIATE_TEST_ES3_AND(TransformFeedbackTest, ES3_VULKAN() diff --git a/src/tests/gl_tests/UniformBufferTest.cpp b/src/tests/gl_tests/UniformBufferTest.cpp index 4d005c0..71b8504 100644 --- a/src/tests/gl_tests/UniformBufferTest.cpp +++ b/src/tests/gl_tests/UniformBufferTest.cpp @@ -3422,6 +3422,50 @@ void main() { EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } +// Calling BufferData and use it in a loop to force descriptorSet creation and destroy. +TEST_P(UniformBufferTest, BufferDataInLoop) +{ + glClear(GL_COLOR_BUFFER_BIT); + + // Use large buffer size to get around suballocation, so that we will gets a new buffer with + // bufferData call. + static constexpr size_t kBufferSize = 4 * 1024 * 1024; + std::vector floatData; + floatData.resize(kBufferSize / (sizeof(float)), 0.0f); + floatData[0] = 0.5f; + floatData[1] = 0.75f; + floatData[2] = 0.25f; + floatData[3] = 1.0f; + + GLTexture textures[2]; + GLFramebuffer fbos[2]; + for (int i = 0; i < 2; i++) + { + glBindTexture(GL_TEXTURE_2D, textures[i]); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); + + glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[i], 0); + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); + } + + for (int loop = 0; loop < 10; loop++) + { + int i = loop & 0x1; + // Switch FBO to get around deferred flush + glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]); + glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer); + glBufferData(GL_UNIFORM_BUFFER, kBufferSize, floatData.data(), GL_STATIC_DRAW); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer); + glUniformBlockBinding(mProgram, mUniformBufferIndex, 0); + drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f); + glFlush(); + } + ASSERT_GL_NO_ERROR(); + EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1); +} + class WebGL2UniformBufferTest : public UniformBufferTest { protected: diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp index 996bad1..11cadf6 100644 --- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp +++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp @@ -5284,8 +5284,8 @@ void main() constexpr char kVSArrayTooLarge[] = R"(varying vec4 color; -// 1 MB / 32 aligned bytes per mat2 = 32768 -const int array_size = 32769; +// 16 MB / 32 aligned bytes per mat2 = 524288 +const int array_size = 524289; void main() { mat2 array[array_size]; @@ -5297,7 +5297,7 @@ void main() constexpr char kVSArrayMuchTooLarge[] = R"(varying vec4 color; -const int array_size = 55600; +const int array_size = 757000; void main() { mat2 array[array_size]; @@ -5361,9 +5361,9 @@ TEST_P(WebGLCompatibilityTest, ValidateTotalPrivateSize) constexpr char kTooLargeGlobalMemory1[] = R"(precision mediump float; -// 1 MB / 16 bytes per vec4 = 65536 -vec4 array[32768]; -vec4 array2[32769]; +// 16 MB / 16 bytes per vec4 = 1048576 +vec4 array[524288]; +vec4 array2[524289]; void main() { @@ -5376,9 +5376,9 @@ void main() constexpr char kTooLargeGlobalMemory2[] = R"(precision mediump float; -// 1 MB / 16 bytes per vec4 = 65536 -vec4 array[32767]; -vec4 array2[32767]; +// 16 MB / 16 bytes per vec4 = 1048576 +vec4 array[524287]; +vec4 array2[524287]; vec4 x, y, z; void main() @@ -5392,12 +5392,12 @@ void main() constexpr char kTooLargeGlobalAndLocalMemory1[] = R"(precision mediump float; -// 1 MB / 16 bytes per vec4 = 65536 -vec4 array[32768]; +// 16 MB / 16 bytes per vec4 = 1048576 +vec4 array[524288]; void main() { - vec4 array2[32769]; + vec4 array2[524289]; if (array[0].x + array[1].x == 2.0) gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); else @@ -5408,25 +5408,25 @@ void main() constexpr char kTooLargeGlobalAndLocalMemory2[] = R"(precision mediump float; -// 1 MB / 16 bytes per vec4 = 65536 -vec4 array[32768]; +// 16 MB / 16 bytes per vec4 = 1048576 +vec4 array[524288]; float f() { - vec4 array2[16384]; + vec4 array2[524288]; return array2[0].x; } float g() { - vec4 array3[16383]; + vec4 array3[524287]; return array3[0].x; } float h() { vec4 value; - float value2 + float value2; return value.x + value2; } @@ -5438,6 +5438,131 @@ void main() gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); })"; + constexpr char kTooLargeGlobalMemoryOverflow[] = + R"(precision mediump float; + +// 16 MB / 16 bytes per vec4 = 1048576 +// Create 256 arrays so each is small, but the total overflows a 32-bit number +vec4 array[1048576], array2[1048576], array3[1048576], array4[1048576], array5[1048576]; +vec4 array6[1048576], array7[1048576], array8[1048576], array9[1048576], array10[1048576]; +vec4 array11[1048576], array12[1048576], array13[1048576], array14[1048576], array15[1048576]; +vec4 array16[1048576], array17[1048576], array18[1048576], array19[1048576], array20[1048576]; +vec4 array21[1048576], array22[1048576], array23[1048576], array24[1048576], array25[1048576]; +vec4 array26[1048576], array27[1048576], array28[1048576], array29[1048576], array30[1048576]; +vec4 array31[1048576], array32[1048576], array33[1048576], array34[1048576], array35[1048576]; +vec4 array36[1048576], array37[1048576], array38[1048576], array39[1048576], array40[1048576]; +vec4 array41[1048576], array42[1048576], array43[1048576], array44[1048576], array45[1048576]; +vec4 array46[1048576], array47[1048576], array48[1048576], array49[1048576], array50[1048576]; +vec4 array51[1048576], array52[1048576], array53[1048576], array54[1048576], array55[1048576]; +vec4 array56[1048576], array57[1048576], array58[1048576], array59[1048576], array60[1048576]; +vec4 array61[1048576], array62[1048576], array63[1048576], array64[1048576], array65[1048576]; +vec4 array66[1048576], array67[1048576], array68[1048576], array69[1048576], array70[1048576]; +vec4 array71[1048576], array72[1048576], array73[1048576], array74[1048576], array75[1048576]; +vec4 array76[1048576], array77[1048576], array78[1048576], array79[1048576], array80[1048576]; +vec4 array81[1048576], array82[1048576], array83[1048576], array84[1048576], array85[1048576]; +vec4 array86[1048576], array87[1048576], array88[1048576], array89[1048576], array90[1048576]; +vec4 array91[1048576], array92[1048576], array93[1048576], array94[1048576], array95[1048576]; +vec4 array96[1048576], array97[1048576], array98[1048576], array99[1048576], array100[1048576]; +vec4 array101[1048576], array102[1048576], array103[1048576], array104[1048576], array105[1048576]; +vec4 array106[1048576], array107[1048576], array108[1048576], array109[1048576], array110[1048576]; +vec4 array111[1048576], array112[1048576], array113[1048576], array114[1048576], array115[1048576]; +vec4 array116[1048576], array117[1048576], array118[1048576], array119[1048576], array120[1048576]; +vec4 array121[1048576], array122[1048576], array123[1048576], array124[1048576], array125[1048576]; +vec4 array126[1048576], array127[1048576], array128[1048576], array129[1048576], array130[1048576]; +vec4 array131[1048576], array132[1048576], array133[1048576], array134[1048576], array135[1048576]; +vec4 array136[1048576], array137[1048576], array138[1048576], array139[1048576], array140[1048576]; +vec4 array141[1048576], array142[1048576], array143[1048576], array144[1048576], array145[1048576]; +vec4 array146[1048576], array147[1048576], array148[1048576], array149[1048576], array150[1048576]; +vec4 array151[1048576], array152[1048576], array153[1048576], array154[1048576], array155[1048576]; +vec4 array156[1048576], array157[1048576], array158[1048576], array159[1048576], array160[1048576]; +vec4 array161[1048576], array162[1048576], array163[1048576], array164[1048576], array165[1048576]; +vec4 array166[1048576], array167[1048576], array168[1048576], array169[1048576], array170[1048576]; +vec4 array171[1048576], array172[1048576], array173[1048576], array174[1048576], array175[1048576]; +vec4 array176[1048576], array177[1048576], array178[1048576], array179[1048576], array180[1048576]; +vec4 array181[1048576], array182[1048576], array183[1048576], array184[1048576], array185[1048576]; +vec4 array186[1048576], array187[1048576], array188[1048576], array189[1048576], array190[1048576]; +vec4 array191[1048576], array192[1048576], array193[1048576], array194[1048576], array195[1048576]; +vec4 array196[1048576], array197[1048576], array198[1048576], array199[1048576], array200[1048576]; +vec4 array201[1048576], array202[1048576], array203[1048576], array204[1048576], array205[1048576]; +vec4 array206[1048576], array207[1048576], array208[1048576], array209[1048576], array210[1048576]; +vec4 array211[1048576], array212[1048576], array213[1048576], array214[1048576], array215[1048576]; +vec4 array216[1048576], array217[1048576], array218[1048576], array219[1048576], array220[1048576]; +vec4 array221[1048576], array222[1048576], array223[1048576], array224[1048576], array225[1048576]; +vec4 array226[1048576], array227[1048576], array228[1048576], array229[1048576], array230[1048576]; +vec4 array231[1048576], array232[1048576], array233[1048576], array234[1048576], array235[1048576]; +vec4 array236[1048576], array237[1048576], array238[1048576], array239[1048576], array240[1048576]; +vec4 array241[1048576], array242[1048576], array243[1048576], array244[1048576], array245[1048576]; +vec4 array246[1048576], array247[1048576], array248[1048576], array249[1048576], array250[1048576]; +vec4 array251[1048576], array252[1048576], array253[1048576], array254[1048576], array255[1048576]; +vec4 array256[1048576]; + +void main() +{ + float f = array[0].x; f += array2[0].x; f += array3[0].x; f += array4[0].x; f += array5[0].x; + f += array6[0].x; f += array7[0].x; f += array8[0].x; f += array9[0].x; f += array10[0].x; + f += array11[0].x; f += array12[0].x; f += array13[0].x; f += array14[0].x; f += array15[0].x; + f += array16[0].x; f += array17[0].x; f += array18[0].x; f += array19[0].x; f += array20[0].x; + f += array21[0].x; f += array22[0].x; f += array23[0].x; f += array24[0].x; f += array25[0].x; + f += array26[0].x; f += array27[0].x; f += array28[0].x; f += array29[0].x; f += array30[0].x; + f += array31[0].x; f += array32[0].x; f += array33[0].x; f += array34[0].x; f += array35[0].x; + f += array36[0].x; f += array37[0].x; f += array38[0].x; f += array39[0].x; f += array40[0].x; + f += array41[0].x; f += array42[0].x; f += array43[0].x; f += array44[0].x; f += array45[0].x; + f += array46[0].x; f += array47[0].x; f += array48[0].x; f += array49[0].x; f += array50[0].x; + f += array51[0].x; f += array52[0].x; f += array53[0].x; f += array54[0].x; f += array55[0].x; + f += array56[0].x; f += array57[0].x; f += array58[0].x; f += array59[0].x; f += array60[0].x; + f += array61[0].x; f += array62[0].x; f += array63[0].x; f += array64[0].x; f += array65[0].x; + f += array66[0].x; f += array67[0].x; f += array68[0].x; f += array69[0].x; f += array70[0].x; + f += array71[0].x; f += array72[0].x; f += array73[0].x; f += array74[0].x; f += array75[0].x; + f += array76[0].x; f += array77[0].x; f += array78[0].x; f += array79[0].x; f += array80[0].x; + f += array81[0].x; f += array82[0].x; f += array83[0].x; f += array84[0].x; f += array85[0].x; + f += array86[0].x; f += array87[0].x; f += array88[0].x; f += array89[0].x; f += array90[0].x; + f += array91[0].x; f += array92[0].x; f += array93[0].x; f += array94[0].x; f += array95[0].x; + f += array96[0].x; f += array97[0].x; f += array98[0].x; f += array99[0].x; f += array100[0].x; + f += array101[0].x; f += array102[0].x; f += array103[0].x; f += array104[0].x; + f += array105[0].x; f += array106[0].x; f += array107[0].x; f += array108[0].x; + f += array109[0].x; f += array110[0].x; f += array111[0].x; f += array112[0].x; + f += array113[0].x; f += array114[0].x; f += array115[0].x; f += array116[0].x; + f += array117[0].x; f += array118[0].x; f += array119[0].x; f += array120[0].x; + f += array121[0].x; f += array122[0].x; f += array123[0].x; f += array124[0].x; + f += array125[0].x; f += array126[0].x; f += array127[0].x; f += array128[0].x; + f += array129[0].x; f += array130[0].x; f += array131[0].x; f += array132[0].x; + f += array133[0].x; f += array134[0].x; f += array135[0].x; f += array136[0].x; + f += array137[0].x; f += array138[0].x; f += array139[0].x; f += array140[0].x; + f += array141[0].x; f += array142[0].x; f += array143[0].x; f += array144[0].x; + f += array145[0].x; f += array146[0].x; f += array147[0].x; f += array148[0].x; + f += array149[0].x; f += array150[0].x; f += array151[0].x; f += array152[0].x; + f += array153[0].x; f += array154[0].x; f += array155[0].x; f += array156[0].x; + f += array157[0].x; f += array158[0].x; f += array159[0].x; f += array160[0].x; + f += array161[0].x; f += array162[0].x; f += array163[0].x; f += array164[0].x; + f += array165[0].x; f += array166[0].x; f += array167[0].x; f += array168[0].x; + f += array169[0].x; f += array170[0].x; f += array171[0].x; f += array172[0].x; + f += array173[0].x; f += array174[0].x; f += array175[0].x; f += array176[0].x; + f += array177[0].x; f += array178[0].x; f += array179[0].x; f += array180[0].x; + f += array181[0].x; f += array182[0].x; f += array183[0].x; f += array184[0].x; + f += array185[0].x; f += array186[0].x; f += array187[0].x; f += array188[0].x; + f += array189[0].x; f += array190[0].x; f += array191[0].x; f += array192[0].x; + f += array193[0].x; f += array194[0].x; f += array195[0].x; f += array196[0].x; + f += array197[0].x; f += array198[0].x; f += array199[0].x; f += array200[0].x; + f += array201[0].x; f += array202[0].x; f += array203[0].x; f += array204[0].x; + f += array205[0].x; f += array206[0].x; f += array207[0].x; f += array208[0].x; + f += array209[0].x; f += array210[0].x; f += array211[0].x; f += array212[0].x; + f += array213[0].x; f += array214[0].x; f += array215[0].x; f += array216[0].x; + f += array217[0].x; f += array218[0].x; f += array219[0].x; f += array220[0].x; + f += array221[0].x; f += array222[0].x; f += array223[0].x; f += array224[0].x; + f += array225[0].x; f += array226[0].x; f += array227[0].x; f += array228[0].x; + f += array229[0].x; f += array230[0].x; f += array231[0].x; f += array232[0].x; + f += array233[0].x; f += array234[0].x; f += array235[0].x; f += array236[0].x; + f += array237[0].x; f += array238[0].x; f += array239[0].x; f += array240[0].x; + f += array241[0].x; f += array242[0].x; f += array243[0].x; f += array244[0].x; + f += array245[0].x; f += array246[0].x; f += array247[0].x; f += array248[0].x; + f += array249[0].x; f += array250[0].x; f += array251[0].x; f += array252[0].x; + f += array253[0].x; f += array254[0].x; f += array255[0].x; f += array256[0].x; + if (f == 2.0) + gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); + else + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); +})"; + GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory1); EXPECT_EQ(0u, program); @@ -5449,6 +5574,9 @@ void main() program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2); EXPECT_EQ(0u, program); + + program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemoryOverflow); + EXPECT_EQ(0u, program); } // Linking should fail when corresponding vertex/fragment uniform blocks have different precision @@ -5975,6 +6103,26 @@ TEST_P(WebGL2CompatibilityTest, TexImageSyncWithIncompleteFramebufferBug) glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 8, 8, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, nullptr); } +// Test for a mishandling of instanced vertex attributes with zero-sized buffers bound on Apple +// OpenGL drivers. +TEST_P(WebGL2CompatibilityTest, DrawWithZeroSizedBuffer) +{ + ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); + glUseProgram(program); + + GLBuffer buffer; + glBindBuffer(GL_ARRAY_BUFFER, buffer); + + GLint posLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib()); + glEnableVertexAttribArray(posLocation); + + glVertexAttribDivisor(posLocation, 1); + glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 9, + reinterpret_cast(0x41424344)); + + glDrawArrays(GL_TRIANGLES, 0, 6); +} + ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2CompatibilityTest); diff --git a/util/angle_features_autogen.cpp b/util/angle_features_autogen.cpp index 63a7ce1..b31ec46 100644 --- a/util/angle_features_autogen.cpp +++ b/util/angle_features_autogen.cpp @@ -133,6 +133,7 @@ constexpr PackedEnumMap kFeatureNames = {{ {Feature::EnableProgramBinaryForCapture, "enableProgramBinaryForCapture"}, {Feature::EnableShaderSubstitution, "enableShaderSubstitution"}, {Feature::EnableTimestampQueries, "enableTimestampQueries"}, + {Feature::EnsureNonEmptyBufferIsBoundForDraw, "ensureNonEmptyBufferIsBoundForDraw"}, {Feature::ExpandIntegerPowExpressions, "expandIntegerPowExpressions"}, {Feature::ExplicitlyCastMediumpFloatTo16Bit, "explicitlyCastMediumpFloatTo16Bit"}, {Feature::ExplicitlyEnablePerSampleShading, "explicitlyEnablePerSampleShading"}, diff --git a/util/angle_features_autogen.h b/util/angle_features_autogen.h index 565b97b..d76d3f6 100644 --- a/util/angle_features_autogen.h +++ b/util/angle_features_autogen.h @@ -126,6 +126,7 @@ enum class Feature EnableProgramBinaryForCapture, EnableShaderSubstitution, EnableTimestampQueries, + EnsureNonEmptyBufferIsBoundForDraw, ExpandIntegerPowExpressions, ExplicitlyCastMediumpFloatTo16Bit, ExplicitlyEnablePerSampleShading, -- Gitee