Pass preserveInvariance to MSL compiler if necessary

Fixed: dawn:977
Change-Id: I7df2080424a4af0b7155ee24f61bb37f0674de82
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/57741
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/dawn_native/metal/ShaderModuleMTL.h b/src/dawn_native/metal/ShaderModuleMTL.h
index 2cfdf49..da42d46 100644
--- a/src/dawn_native/metal/ShaderModuleMTL.h
+++ b/src/dawn_native/metal/ShaderModuleMTL.h
@@ -58,7 +58,8 @@
                                                           const RenderPipeline* renderPipeline,
                                                           const VertexState* vertexState,
                                                           std::string* remappedEntryPointName,
-                                                          bool* needsStorageBufferLength);
+                                                          bool* needsStorageBufferLength,
+                                                          bool* hasInvariantAttribute);
         ResultOrError<std::string> TranslateToMSLWithSPIRVCross(
             const char* entryPointName,
             SingleShaderStage stage,
diff --git a/src/dawn_native/metal/ShaderModuleMTL.mm b/src/dawn_native/metal/ShaderModuleMTL.mm
index d2475e05..bbbe86c 100644
--- a/src/dawn_native/metal/ShaderModuleMTL.mm
+++ b/src/dawn_native/metal/ShaderModuleMTL.mm
@@ -59,7 +59,8 @@
         const RenderPipeline* renderPipeline,
         const VertexState* vertexState,
         std::string* remappedEntryPointName,
-        bool* needsStorageBufferLength) {
+        bool* needsStorageBufferLength,
+        bool* hasInvariantAttribute) {
         ScopedTintICEHandler scopedICEHandler(GetDevice());
 
         std::ostringstream errorStream;
@@ -160,6 +161,7 @@
         }
 
         *needsStorageBufferLength = result.needs_storage_buffer_sizes;
+        *hasInvariantAttribute = result.has_invariant_attribute;
 
         return std::move(result.msl);
     }
@@ -292,11 +294,12 @@
 
         std::string remappedEntryPointName;
         std::string msl;
+        bool hasInvariantAttribute = false;
         if (GetDevice()->IsToggleEnabled(Toggle::UseTintGenerator)) {
-            DAWN_TRY_ASSIGN(
-                msl, TranslateToMSLWithTint(entryPointName, stage, layout, sampleMask,
-                                            renderPipeline, vertexState, &remappedEntryPointName,
-                                            &out->needsStorageBufferLength));
+            DAWN_TRY_ASSIGN(msl, TranslateToMSLWithTint(
+                                     entryPointName, stage, layout, sampleMask, renderPipeline,
+                                     vertexState, &remappedEntryPointName,
+                                     &out->needsStorageBufferLength, &hasInvariantAttribute));
         } else {
             DAWN_TRY_ASSIGN(msl, TranslateToMSLWithSPIRVCross(entryPointName, stage, layout,
                                                               sampleMask, renderPipeline,
@@ -322,11 +325,17 @@
 
         NSRef<NSString> mslSource = AcquireNSRef([[NSString alloc] initWithUTF8String:msl.c_str()]);
 
+        NSRef<MTLCompileOptions> compileOptions = AcquireNSRef([[MTLCompileOptions alloc] init]);
+        if (hasInvariantAttribute) {
+            if (@available(macOS 11.0, iOS 13.0, *)) {
+                (*compileOptions).preserveInvariance = true;
+            }
+        }
         auto mtlDevice = ToBackend(GetDevice())->GetMTLDevice();
         NSError* error = nullptr;
         NSPRef<id<MTLLibrary>> library =
             AcquireNSPRef([mtlDevice newLibraryWithSource:mslSource.Get()
-                                                  options:nullptr
+                                                  options:compileOptions.Get()
                                                     error:&error]);
         if (error != nullptr) {
             if (error.code != MTLLibraryErrorCompileWarning) {