diff options
author | Alexey Knyazev <lexa.knyazev@gmail.com> | 2023-11-30 00:00:00 +0000 |
---|---|---|
committer | Angle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-12-06 18:54:35 +0000 |
commit | 6d9f0aee9026e09f667d8d06459b8f25d11c4bc7 (patch) | |
tree | 38328c8ea4bf81590bed139e427e35a0e972a42d | |
parent | ac4cb7083f5f4ed3487243bc98ce1d68108fc14d (diff) | |
download | angle-6d9f0aee9026e09f667d8d06459b8f25d11c4bc7.tar.gz |
Metal: Ensure helper invocations when derivatives are used
Set sample coverage mask to ensure that
fragment shader helper invocations are
performed when derivatives are used.
Fixed the following tests on Apple silicon:
dEQP-GLES2.functional.texture.mipmap
.2d.projected.nearest_linear_repeat
.2d.projected.linear_linear_repeat
.cube.projected.linear_nearest
.cube.projected.linear_linear
dEQP-GLES3.functional.texture.mipmap
.2d.projected.nearest_nearest_mirror
.2d.projected.linear_nearest_clamp
.2d.projected.linear_nearest_repeat
.2d.projected.linear_nearest_mirror
.2d.projected.nearest_linear_repeat
.2d.projected.linear_linear_clamp
.2d.projected.linear_linear_repeat
.3d.projected.nearest_nearest_mirror
.3d.projected.linear_nearest_clamp
.3d.projected.linear_nearest_repeat
.3d.projected.nearest_linear_clamp
.3d.projected.nearest_linear_mirror
.3d.projected.linear_linear_clamp
.3d.projected.linear_linear_repeat
Fixed: angleproject:8443
Fixed: angleproject:7023
Change-Id: I13fc52532b94de098dcf3e9f5f02d48a6c8913c7
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5089131
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Alexey Knyazev <lexa.knyazev@gmail.com>
-rw-r--r-- | include/GLSLANG/ShaderLang.h | 8 | ||||
-rw-r--r-- | include/platform/autogen/FeaturesMtl_autogen.h | 7 | ||||
-rw-r--r-- | include/platform/mtl_features.json | 7 | ||||
-rw-r--r-- | src/compiler/translator/Compiler.cpp | 3 | ||||
-rw-r--r-- | src/compiler/translator/Compiler.h | 5 | ||||
-rw-r--r-- | src/compiler/translator/ParseContext.cpp | 61 | ||||
-rw-r--r-- | src/compiler/translator/ParseContext.h | 2 | ||||
-rw-r--r-- | src/compiler/translator/msl/ConstantNames.cpp | 2 | ||||
-rw-r--r-- | src/compiler/translator/msl/EmitMetal.cpp | 2 | ||||
-rw-r--r-- | src/compiler/translator/msl/ProgramPrelude.cpp | 9 | ||||
-rw-r--r-- | src/compiler/translator/msl/ProgramPrelude.h | 1 | ||||
-rw-r--r-- | src/compiler/translator/msl/TranslatorMSL.cpp | 28 | ||||
-rw-r--r-- | src/libANGLE/renderer/metal/DisplayMtl.mm | 2 | ||||
-rw-r--r-- | src/libANGLE/renderer/metal/ProgramExecutableMtl.mm | 4 | ||||
-rw-r--r-- | util/autogen/angle_features_autogen.cpp | 1 | ||||
-rw-r--r-- | util/autogen/angle_features_autogen.h | 1 |
16 files changed, 139 insertions, 4 deletions
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h index 5740d2f8bd..19e9f77f80 100644 --- a/include/GLSLANG/ShaderLang.h +++ b/include/GLSLANG/ShaderLang.h @@ -26,7 +26,7 @@ // Version number for shader translation API. // It is incremented every time the API changes. -#define ANGLE_SH_VERSION 344 +#define ANGLE_SH_VERSION 345 enum ShShaderSpec { @@ -1116,6 +1116,12 @@ extern const char kDepthWriteEnabledConstName[]; // Specialization constant to enable alpha to coverage. extern const char kEmulateAlphaToCoverageConstName[]; + +// Specialization constant to write helper sample mask output. +extern const char kWriteHelperSampleMaskConstName[]; + +// Specialization constant to enable sample mask output. +extern const char kSampleMaskWriteEnabledConstName[]; } // namespace mtl } // namespace sh diff --git a/include/platform/autogen/FeaturesMtl_autogen.h b/include/platform/autogen/FeaturesMtl_autogen.h index 4cce6f8d93..ecbdefa990 100644 --- a/include/platform/autogen/FeaturesMtl_autogen.h +++ b/include/platform/autogen/FeaturesMtl_autogen.h @@ -206,6 +206,13 @@ struct FeaturesMtl : FeatureSetBase &members, }; + FeatureInfo writeHelperSampleMask = { + "writeHelperSampleMask", + FeatureCategory::MetalWorkarounds, + "Some GPUs produce incorrect derivatives unless [[sample_mask]] is written", + &members, + }; + FeatureInfo preTransformTextureCubeGradDerivatives = { "preTransformTextureCubeGradDerivatives", FeatureCategory::MetalWorkarounds, diff --git a/include/platform/mtl_features.json b/include/platform/mtl_features.json index 786f70d5ed..2784ce3900 100644 --- a/include/platform/mtl_features.json +++ b/include/platform/mtl_features.json @@ -194,6 +194,13 @@ ] }, { + "name": "write_helper_sample_mask", + "category": "Workarounds", + "description": [ + "Some GPUs produce incorrect derivatives unless [[sample_mask]] is written" + ] + }, + { "name": "pre_transform_texture_cube_grad_derivatives", "category": "Workarounds", "description": [ diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp index 1a25aa2ed9..ec49d33b3d 100644 --- a/src/compiler/translator/Compiler.cpp +++ b/src/compiler/translator/Compiler.cpp @@ -376,6 +376,7 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) mHasAnyPreciseType(false), mAdvancedBlendEquations(0), mHasPixelLocalStorageUniforms(false), + mUsesDerivatives(false), mCompileOptions{} {} @@ -594,6 +595,8 @@ void TCompiler::setASTMetadata(const TParseContext &parseContext) mHasAnyPreciseType = parseContext.hasAnyPreciseType(); + mUsesDerivatives = parseContext.usesDerivatives(); + if (mShaderType == GL_FRAGMENT_SHADER) { mAdvancedBlendEquations = parseContext.getAdvancedBlendEquations(); diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h index 67fac62803..8161320ed5 100644 --- a/src/compiler/translator/Compiler.h +++ b/src/compiler/translator/Compiler.h @@ -229,6 +229,8 @@ class TCompiler : public TShHandleBase bool hasClipDistance() const { return mClipDistanceUsed; } + bool usesDerivatives() const { return mUsesDerivatives; } + protected: // Add emulated functions to the built-in function emulator. virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, @@ -389,6 +391,9 @@ class TCompiler : public TShHandleBase // ANGLE_shader_pixel_local_storage. bool mHasPixelLocalStorageUniforms; + // Fragment shader uses screen-space derivatives + bool mUsesDerivatives; + // name hashing. NameMap mNameMap; diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp index 036e9c4bbe..38bd4ca13a 100644 --- a/src/compiler/translator/ParseContext.cpp +++ b/src/compiler/translator/ParseContext.cpp @@ -167,6 +167,61 @@ constexpr bool IsValidWithPixelLocalStorage(TLayoutImageInternalFormat internalF return false; } } + +bool UsesDerivatives(TIntermAggregate *functionCall) +{ + const TOperator op = functionCall->getOp(); + if (BuiltInGroup::IsDerivativesFS(op)) + { + return true; + } + switch (op) + { + // TextureFirstVersions with implicit LOD + case EOpTexture2D: + case EOpTexture2DProj: + case EOpTextureCube: + case EOpTexture1D: + case EOpTexture1DProj: + case EOpTexture3D: + case EOpTexture3DProj: + case EOpShadow1D: + case EOpShadow1DProj: + case EOpShadow2D: + case EOpShadow2DProj: + case EOpShadow2DEXT: + case EOpShadow2DProjEXT: + // TextureFirstVersionsBias + case EOpTexture2DBias: + case EOpTexture2DProjBias: + case EOpTextureCubeBias: + case EOpTexture3DBias: + case EOpTexture3DProjBias: + case EOpTexture1DBias: + case EOpTexture1DProjBias: + case EOpShadow1DBias: + case EOpShadow1DProjBias: + case EOpShadow2DBias: + case EOpShadow2DProjBias: + // TextureNoBias + case EOpTexture: + case EOpTextureProj: + // TextureBias + case EOpTextureBias: + case EOpTextureProjBias: + // TextureQueryLod + case EOpTextureQueryLod: + // TextureOffsetNoBias + case EOpTextureOffset: + case EOpTextureProjOffset: + // TextureOffsetBias + case EOpTextureOffsetBias: + case EOpTextureProjOffsetBias: + return true; + default: + return false; + } +} } // namespace // This tracks each binding point's current default offset for inheritance of subsequent @@ -230,6 +285,7 @@ TParseContext::TParseContext(TSymbolTable &symt, mPositionRedeclaredForSeparateShaderObject(false), mPointSizeRedeclaredForSeparateShaderObject(false), mPositionOrPointSizeUsedForSeparateShaderObject(false), + mUsesDerivatives(false), mDefaultUniformMatrixPacking(EmpColumnMajor), mDefaultUniformBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), mDefaultBufferMatrixPacking(EmpColumnMajor), @@ -7683,6 +7739,11 @@ TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunctionLookup *fnCa TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments()); callNode->setLine(loc); + if (UsesDerivatives(callNode)) + { + mUsesDerivatives = true; + } + checkAtomicMemoryBuiltinFunctions(callNode); checkTextureOffset(callNode); checkTextureGather(callNode); diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h index c83b73271b..78c71b18b8 100644 --- a/src/compiler/translator/ParseContext.h +++ b/src/compiler/translator/ParseContext.h @@ -75,6 +75,7 @@ class TParseContext : angle::NonCopyable mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh; } + bool usesDerivatives() const { return mUsesDerivatives; } bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; } bool hasDiscard() const { return mHasDiscard; } bool isSampleQualifierSpecified() const { return mSampleQualifierSpecified; } @@ -749,6 +750,7 @@ class TParseContext : angle::NonCopyable // enabled and gl_PointSize is redefined. bool mPositionOrPointSizeUsedForSeparateShaderObject; // true if gl_Position or gl_PointSize // has been referenced. + bool mUsesDerivatives; // true if screen-space derivatives are used implicitly or explicitly TLayoutMatrixPacking mDefaultUniformMatrixPacking; TLayoutBlockStorage mDefaultUniformBlockStorage; TLayoutMatrixPacking mDefaultBufferMatrixPacking; diff --git a/src/compiler/translator/msl/ConstantNames.cpp b/src/compiler/translator/msl/ConstantNames.cpp index a82c2fb46f..bae83f4a33 100644 --- a/src/compiler/translator/msl/ConstantNames.cpp +++ b/src/compiler/translator/msl/ConstantNames.cpp @@ -20,6 +20,8 @@ const char kMultisampledRenderingConstName[] = "ANGLEMultisampledRendering"; const char kRasterizerDiscardEnabledConstName[] = "ANGLERasterizerDisabled"; const char kDepthWriteEnabledConstName[] = "ANGLEDepthWriteEnabled"; const char kEmulateAlphaToCoverageConstName[] = "ANGLEEmulateAlphaToCoverage"; +const char kWriteHelperSampleMaskConstName[] = "ANGLEWriteHelperSampleMask"; +const char kSampleMaskWriteEnabledConstName[] = "ANGLESampleMaskWriteEnabled"; } // namespace mtl } // namespace sh diff --git a/src/compiler/translator/msl/EmitMetal.cpp b/src/compiler/translator/msl/EmitMetal.cpp index 258a68d142..a640eafc09 100644 --- a/src/compiler/translator/msl/EmitMetal.cpp +++ b/src/compiler/translator/msl/EmitMetal.cpp @@ -1262,7 +1262,7 @@ void GenMetalTraverser::emitFieldDeclaration(const TField &field, if (field.symbolType() == SymbolType::AngleInternal) { mOut << " [[sample_mask, function_constant(" - << sh::mtl::kMultisampledRenderingConstName << ")]]"; + << sh::mtl::kSampleMaskWriteEnabledConstName << ")]]"; } break; diff --git a/src/compiler/translator/msl/ProgramPrelude.cpp b/src/compiler/translator/msl/ProgramPrelude.cpp index c3203462af..d0463c352b 100644 --- a/src/compiler/translator/msl/ProgramPrelude.cpp +++ b/src/compiler/translator/msl/ProgramPrelude.cpp @@ -50,6 +50,13 @@ class ProgramPrelude : public TIntermTraverser break; case MetalShaderType::Fragment: functionConstants(); + mOut << "constant bool " << mtl::kSampleMaskWriteEnabledConstName << " = " + << mtl::kMultisampledRenderingConstName; + if (ppc.usesDerivatives) + { + mOut << " || " << mtl::kWriteHelperSampleMaskConstName; + } + mOut << ";\n"; break; case MetalShaderType::Compute: ASSERT(0 && "compute shaders not currently supported"); @@ -1557,6 +1564,7 @@ PROGRAM_PRELUDE_DECLARE(functionConstants, #define ANGLE_MULTISAMPLED_RENDERING_INDEX 3 #define ANGLE_DEPTH_WRITE_ENABLED_INDEX 4 #define ANGLE_EMULATE_ALPHA_TO_COVERAGE_INDEX 5 +#define ANGLE_WRITE_HELPER_SAMPLE_MASK_INDEX 6 constant bool ANGLEUseSampleCompareGradient [[function_constant(ANGLE_SAMPLE_COMPARE_GRADIENT_INDEX)]]; constant bool ANGLEUseSampleCompareLod [[function_constant(ANGLE_SAMPLE_COMPARE_LOD_INDEX)]]; @@ -1564,6 +1572,7 @@ constant bool ANGLERasterizerDisabled [[function_constant(ANGLE_RASTERIZAT constant bool ANGLEMultisampledRendering [[function_constant(ANGLE_MULTISAMPLED_RENDERING_INDEX)]]; constant bool ANGLEDepthWriteEnabled [[function_constant(ANGLE_DEPTH_WRITE_ENABLED_INDEX)]]; constant bool ANGLEEmulateAlphaToCoverage [[function_constant(ANGLE_EMULATE_ALPHA_TO_COVERAGE_INDEX)]]; +constant bool ANGLEWriteHelperSampleMask [[function_constant(ANGLE_WRITE_HELPER_SAMPLE_MASK_INDEX)]]; #define ANGLE_ALPHA0 )") diff --git a/src/compiler/translator/msl/ProgramPrelude.h b/src/compiler/translator/msl/ProgramPrelude.h index a60ed386e9..150730132d 100644 --- a/src/compiler/translator/msl/ProgramPrelude.h +++ b/src/compiler/translator/msl/ProgramPrelude.h @@ -32,6 +32,7 @@ struct ProgramPreludeConfig ProgramPreludeConfig() {} explicit ProgramPreludeConfig(MetalShaderType shaderType) : shaderType(shaderType) {} bool hasStructEq = false; + bool usesDerivatives = false; MetalShaderType shaderType = MetalShaderType::None; }; diff --git a/src/compiler/translator/msl/TranslatorMSL.cpp b/src/compiler/translator/msl/TranslatorMSL.cpp index 5c12ab8d35..499ec85c51 100644 --- a/src/compiler/translator/msl/TranslatorMSL.cpp +++ b/src/compiler/translator/msl/TranslatorMSL.cpp @@ -440,6 +440,28 @@ void AddFragDepthEXTDeclaration(TCompiler &compiler, TIntermBlock &root, TSymbol new TType(EbtUInt, EbpHigh, EvqSampleMask, 1), SymbolType::AngleInternal); DeclareRightBeforeMain(root, *angleSampleMask); + // Write all-enabled sample mask even for single-sampled rendering + // when the shader uses derivatives to workaround a driver bug. + if (compiler.usesDerivatives()) + { + TIntermBlock *helperAssignBlock = new TIntermBlock; + helperAssignBlock->appendStatement(new TIntermBinary( + EOpAssign, new TIntermSymbol(angleSampleMask), CreateUIntNode(0xFFFFFFFFu))); + + TVariable *writeHelperSampleMaskVar = + new TVariable(&symbolTable, sh::ImmutableString(mtl::kWriteHelperSampleMaskConstName), + StaticType::Get<EbtBool, EbpUndefined, EvqSpecConst, 1, 1>(), + SymbolType::AngleInternal); + + if (!RunAtTheBeginningOfShader( + &compiler, &root, + new TIntermIfElse(new TIntermSymbol(writeHelperSampleMaskVar), helperAssignBlock, + nullptr))) + { + return false; + } + } + // ANGLE_metal_SampleMask = ANGLE_angleUniforms.coverageMask; TIntermBlock *block = new TIntermBlock; block->appendStatement(new TIntermBinary(EOpAssign, new TIntermSymbol(angleSampleMask), @@ -632,12 +654,13 @@ void AddFragDepthEXTDeclaration(TCompiler &compiler, TIntermBlock &root, TSymbol } // Sample mask assignment is guarded by ANGLEMultisampledRendering specialization constant - TVariable *sampleMaskEnabledVar = new TVariable( + TVariable *multisampledRenderingVar = new TVariable( &symbolTable, sh::ImmutableString(mtl::kMultisampledRenderingConstName), StaticType::Get<EbtBool, EbpUndefined, EvqSpecConst, 1, 1>(), SymbolType::AngleInternal); return RunAtTheEndOfShader( &compiler, &root, - new TIntermIfElse(new TIntermSymbol(sampleMaskEnabledVar), block, nullptr), &symbolTable); + new TIntermIfElse(new TIntermSymbol(multisampledRenderingVar), block, nullptr), + &symbolTable); } [[nodiscard]] bool AddFragDataDeclaration(TCompiler &compiler, @@ -947,6 +970,7 @@ bool TranslatorMSL::translateImpl(TInfoSinkBase &sink, TSymbolTable &symbolTable = getSymbolTable(); IdGen idGen; ProgramPreludeConfig ppc(metalShaderTypeFromGLSL(getShaderType())); + ppc.usesDerivatives = usesDerivatives(); if (!WrapMain(*this, idGen, *root)) { diff --git a/src/libANGLE/renderer/metal/DisplayMtl.mm b/src/libANGLE/renderer/metal/DisplayMtl.mm index b5ebb35289..f1737c9604 100644 --- a/src/libANGLE/renderer/metal/DisplayMtl.mm +++ b/src/libANGLE/renderer/metal/DisplayMtl.mm @@ -1304,6 +1304,8 @@ void DisplayMtl::initializeFeatures() ANGLE_FEATURE_CONDITION((&mFeatures), emulateAlphaToCoverage, isSimulator || !supportsAppleGPUFamily(1)); + ANGLE_FEATURE_CONDITION((&mFeatures), writeHelperSampleMask, supportsAppleGPUFamily(1)); + ANGLE_FEATURE_CONDITION((&mFeatures), multisampleColorFormatShaderReadWorkaround, isAMD()); ANGLE_FEATURE_CONDITION((&mFeatures), copyIOSurfaceToNonIOSurfaceForReadOptimization, isIntel() || isAMD()); diff --git a/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm b/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm index d7e21ea1aa..1fdfeca550 100644 --- a/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm +++ b/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm @@ -1051,6 +1051,10 @@ angle::Result ProgramExecutableMtl::getSpecializedShader( setConstantValue:&(context->getDisplay()->getFeatures().emulateAlphaToCoverage.enabled) type:MTLDataTypeBool withName:@"ANGLEEmulateAlphaToCoverage"]; + [funcConstants + setConstantValue:&(context->getDisplay()->getFeatures().writeHelperSampleMask.enabled) + type:MTLDataTypeBool + withName:@"ANGLEWriteHelperSampleMask"]; // Create Metal shader object ANGLE_MTL_OBJC_SCOPE { diff --git a/util/autogen/angle_features_autogen.cpp b/util/autogen/angle_features_autogen.cpp index 395b59dda3..5831ffef42 100644 --- a/util/autogen/angle_features_autogen.cpp +++ b/util/autogen/angle_features_autogen.cpp @@ -391,6 +391,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{ {Feature::VertexIDDoesNotIncludeBaseVertex, "vertexIDDoesNotIncludeBaseVertex"}, {Feature::WaitIdleBeforeSwapchainRecreation, "waitIdleBeforeSwapchainRecreation"}, {Feature::WarmUpPipelineCacheAtLink, "warmUpPipelineCacheAtLink"}, + {Feature::WriteHelperSampleMask, "writeHelperSampleMask"}, {Feature::ZeroMaxLodWorkaround, "zeroMaxLodWorkaround"}, }}; } // anonymous namespace diff --git a/util/autogen/angle_features_autogen.h b/util/autogen/angle_features_autogen.h index 65dfed07be..17659b0e8b 100644 --- a/util/autogen/angle_features_autogen.h +++ b/util/autogen/angle_features_autogen.h @@ -391,6 +391,7 @@ enum class Feature VertexIDDoesNotIncludeBaseVertex, WaitIdleBeforeSwapchainRecreation, WarmUpPipelineCacheAtLink, + WriteHelperSampleMask, ZeroMaxLodWorkaround, InvalidEnum, |