diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc index ddb3f174ab..4982639d80 100644 --- a/src/writer/msl/generator_impl.cc +++ b/src/writer/msl/generator_impl.cc @@ -240,6 +240,18 @@ bool GeneratorImpl::Generate() { line(); } + if (!invariant_define_name_.empty()) { + // 'invariant' attribute requires MSL 2.1 or higher. + // WGSL can ignore the invariant attribute on pre MSL 2.1 devices. + // See: https://github.com/gpuweb/gpuweb/issues/893#issuecomment-745537465 + line(&helpers_) << "#if __METAL_VERSION__ >= 210"; + line(&helpers_) << "#define " << invariant_define_name_ << " [[invariant]]"; + line(&helpers_) << "#else"; + line(&helpers_) << "#define " << invariant_define_name_; + line(&helpers_) << "#endif"; + line(&helpers_); + } + if (!helpers_.lines.empty()) { current_buffer_->Insert("", helpers_insertion_point++, 0); current_buffer_->Insert(helpers_, helpers_insertion_point++, 0); @@ -2504,8 +2516,10 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) { } out << " [[" << attr << "]]"; } else if (deco->Is()) { - out << " [[invariant]]"; - has_invariant_ = true; + if (invariant_define_name_.empty()) { + invariant_define_name_ = UniqueIdentifier("TINT_INVARIANT"); + } + out << " " << invariant_define_name_; } else if (!deco->IsAnyOf()) { diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h index 710b8e2375..da9971686d 100644 --- a/src/writer/msl/generator_impl.h +++ b/src/writer/msl/generator_impl.h @@ -98,7 +98,7 @@ class GeneratorImpl : public TextGenerator { bool Generate(); /// @returns true if an invariant attribute was generated - bool HasInvariant() { return has_invariant_; } + bool HasInvariant() { return !invariant_define_name_.empty(); } /// @returns a map from entry point to list of required workgroup allocations const std::unordered_map>& @@ -410,8 +410,9 @@ class GeneratorImpl : public TextGenerator { /// class. StorageClassToString atomicCompareExchangeWeak_; - /// True if an invariant attribute has been generated. - bool has_invariant_ = false; + /// Unique name of the 'TINT_INVARIANT' preprocessor define. Non-empty only if + /// an invariant attribute has been generated. + std::string invariant_define_name_; /// True if matrix-packed_vector operator overloads have been generated. bool matrix_packed_vector_overloads_ = false; diff --git a/src/writer/msl/generator_impl_test.cc b/src/writer/msl/generator_impl_test.cc index 121321c7e4..8aa2891dc6 100644 --- a/src/writer/msl/generator_impl_test.cc +++ b/src/writer/msl/generator_impl_test.cc @@ -95,8 +95,15 @@ TEST_F(MslGeneratorImplTest, HasInvariantAttribute_True) { EXPECT_EQ(gen.result(), R"(#include using namespace metal; + +#if __METAL_VERSION__ >= 210 +#define TINT_INVARIANT [[invariant]] +#else +#define TINT_INVARIANT +#endif + struct Out { - float4 pos [[position]] [[invariant]]; + float4 pos [[position]] TINT_INVARIANT; }; vertex Out vert_main() { diff --git a/test/shader_io/invariant.wgsl.expected.msl b/test/shader_io/invariant.wgsl.expected.msl index c9eb97e75b..59822163dc 100644 --- a/test/shader_io/invariant.wgsl.expected.msl +++ b/test/shader_io/invariant.wgsl.expected.msl @@ -1,8 +1,15 @@ #include using namespace metal; + +#if __METAL_VERSION__ >= 210 +#define TINT_INVARIANT [[invariant]] +#else +#define TINT_INVARIANT +#endif + struct tint_symbol_1 { - float4 value [[position]] [[invariant]]; + float4 value [[position]] TINT_INVARIANT; }; float4 tint_symbol_inner() { diff --git a/test/shader_io/invariant_struct_member.wgsl.expected.msl b/test/shader_io/invariant_struct_member.wgsl.expected.msl index a2c44a7d14..c85f9a1271 100644 --- a/test/shader_io/invariant_struct_member.wgsl.expected.msl +++ b/test/shader_io/invariant_struct_member.wgsl.expected.msl @@ -1,11 +1,18 @@ #include using namespace metal; + +#if __METAL_VERSION__ >= 210 +#define TINT_INVARIANT [[invariant]] +#else +#define TINT_INVARIANT +#endif + struct Out { float4 pos; }; struct tint_symbol_1 { - float4 pos [[position]] [[invariant]]; + float4 pos [[position]] TINT_INVARIANT; }; Out tint_symbol_inner() {