Disable multiple mip levels for r8/rg8unorm textures on Metal

Bug: dawn:1071
Change-Id: I2cc9173f0dff325e4bb2583bb27a98bbaaa61531
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63462
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
(cherry picked from commit 1934e56159c9594bc645dad36a5a8b5354f5cbcb)
No-Try: true
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64660
Reviewed-by: Brandon Jones <bajones@chromium.org>
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 889d706..21e378b 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -311,6 +311,14 @@
                 "disabled on Metal.");
         }
 
+        if (device->IsToggleEnabled(Toggle::DisableR8RG8Mipmaps) && descriptor->mipLevelCount > 1 &&
+            (descriptor->format == wgpu::TextureFormat::R8Unorm ||
+             descriptor->format == wgpu::TextureFormat::RG8Unorm)) {
+            return DAWN_VALIDATION_ERROR(
+                "https://crbug.com/dawn/1071: r8unorm and rg8unorm textures with more than one mip "
+                "level are disabled on Metal.");
+        }
+
         return {};
     }
 
diff --git a/src/dawn_native/Toggles.cpp b/src/dawn_native/Toggles.cpp
index 7c40fe7..6b35aeb 100644
--- a/src/dawn_native/Toggles.cpp
+++ b/src/dawn_native/Toggles.cpp
@@ -217,6 +217,11 @@
               "Enables calls to SetLabel to be forwarded to backend-specific APIs that label "
               "objects.",
               "https://crbug.com/dawn/840"}},
+            {Toggle::DisableR8RG8Mipmaps,
+             {"disable_r8_rg8_mipmaps",
+              "Disables mipmaps for r8unorm and rg8unorm textures, which are known on some drivers "
+              "to not clear correctly.",
+              "https://crbug.com/dawn/1071"}},
             // Dummy comment to separate the }} so it is clearer what to copy-paste to add a toggle.
         }};
     }  // anonymous namespace
diff --git a/src/dawn_native/Toggles.h b/src/dawn_native/Toggles.h
index 668086f..eccfb21 100644
--- a/src/dawn_native/Toggles.h
+++ b/src/dawn_native/Toggles.h
@@ -59,6 +59,7 @@
         DisableWorkgroupInit,
         DisableSymbolRenaming,
         UseUserDefinedLabelsInBackend,
+        DisableR8RG8Mipmaps,
 
         EnumCount,
         InvalidEnum = EnumCount,
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 664f2c6..5abdeb5 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -199,13 +199,21 @@
         // TODO(crbug.com/dawn/846): tighten this workaround when the driver bug is fixed.
         SetToggle(Toggle::AlwaysResolveIntoZeroLevelAndLayer, true);
 
+        const PCIInfo& pciInfo = GetAdapter()->GetPCIInfo();
+
         // TODO(crbug.com/dawn/847): Use MTLStorageModeShared instead of MTLStorageModePrivate when
         // creating MTLCounterSampleBuffer in QuerySet on Intel platforms, otherwise it fails to
         // create the buffer. Change to use MTLStorageModePrivate when the bug is fixed.
         if (@available(macOS 10.15, iOS 14.0, *)) {
-            bool useSharedMode = gpu_info::IsIntel(this->GetAdapter()->GetPCIInfo().vendorId);
+            bool useSharedMode = gpu_info::IsIntel(pciInfo.vendorId);
             SetToggle(Toggle::MetalUseSharedModeForCounterSampleBuffer, useSharedMode);
         }
+
+        // TODO(crbug.com/dawn/1071): r8unorm and rg8unorm textures with multiple mip levels don't
+        // clear properly on Intel Macs.
+        if (gpu_info::IsIntel(pciInfo.vendorId)) {
+            SetToggle(Toggle::DisableR8RG8Mipmaps, true);
+        }
     }
 
     ResultOrError<Ref<BindGroupBase>> Device::CreateBindGroupImpl(
diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp
index 43bc5ca..f0750a1 100644
--- a/src/tests/end2end/CopyTests.cpp
+++ b/src/tests/end2end/CopyTests.cpp
@@ -2120,6 +2120,11 @@
             continue;
         }
 
+        if (HasToggleEnabled("disable_r8_rg8_mipmaps") &&
+            (format == wgpu::TextureFormat::R8Unorm || format == wgpu::TextureFormat::RG8Unorm)) {
+            continue;
+        }
+
         for (uint32_t textureLayer : kTestTextureLayer) {
             const wgpu::Extent3D kUploadSize = {4u, 4u, textureLayer};
 
diff --git a/src/tests/end2end/NonzeroTextureCreationTests.cpp b/src/tests/end2end/NonzeroTextureCreationTests.cpp
index 783c3ec..6040562 100644
--- a/src/tests/end2end/NonzeroTextureCreationTests.cpp
+++ b/src/tests/end2end/NonzeroTextureCreationTests.cpp
@@ -104,6 +104,12 @@
                  GetParam().mFormat == wgpu::TextureFormat::Depth24PlusStencil8) &&
                 IsMetal() && IsIntel() && GetParam().mMip != 0);
 
+            // TODO(crbug.com/dawn/1071): Implement a workaround on Intel/Metal backends.
+            DAWN_SUPPRESS_TEST_IF((GetParam().mFormat == wgpu::TextureFormat::R8Unorm ||
+                                   GetParam().mFormat == wgpu::TextureFormat::RG8Unorm) &&
+                                  GetParam().mMipCount > 1 &&
+                                  HasToggleEnabled("disable_r8_rg8_mipmaps"));
+
             // Copies from depth textures not fully supported on the OpenGL backend right now.
             DAWN_SUPPRESS_TEST_IF(GetParam().mFormat == wgpu::TextureFormat::Depth32Float &&
                                   (IsOpenGL() || IsOpenGLES()));