aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Knyazev <lexa.knyazev@gmail.com>2023-11-30 00:00:00 +0000
committerAngle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-12-06 18:54:35 +0000
commit6d9f0aee9026e09f667d8d06459b8f25d11c4bc7 (patch)
tree38328c8ea4bf81590bed139e427e35a0e972a42d
parentac4cb7083f5f4ed3487243bc98ce1d68108fc14d (diff)
downloadangle-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.h8
-rw-r--r--include/platform/autogen/FeaturesMtl_autogen.h7
-rw-r--r--include/platform/mtl_features.json7
-rw-r--r--src/compiler/translator/Compiler.cpp3
-rw-r--r--src/compiler/translator/Compiler.h5
-rw-r--r--src/compiler/translator/ParseContext.cpp61
-rw-r--r--src/compiler/translator/ParseContext.h2
-rw-r--r--src/compiler/translator/msl/ConstantNames.cpp2
-rw-r--r--src/compiler/translator/msl/EmitMetal.cpp2
-rw-r--r--src/compiler/translator/msl/ProgramPrelude.cpp9
-rw-r--r--src/compiler/translator/msl/ProgramPrelude.h1
-rw-r--r--src/compiler/translator/msl/TranslatorMSL.cpp28
-rw-r--r--src/libANGLE/renderer/metal/DisplayMtl.mm2
-rw-r--r--src/libANGLE/renderer/metal/ProgramExecutableMtl.mm4
-rw-r--r--util/autogen/angle_features_autogen.cpp1
-rw-r--r--util/autogen/angle_features_autogen.h1
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,