Disallow Multiple Render Targets When Using Dual Source Blending

Because multiple backends do not allow multiple render targets when
using dual source blending, disallow usage of any non-zero render target
outputs when dual source blending is in use.

Bug: dawn:1709
Change-Id: I1430797df9e887298c251a405e0e2defc9f43508
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/146020
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc b/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
index 7c88185..54d9649 100644
--- a/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
+++ b/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
@@ -143,5 +143,33 @@
     EXPECT_EQ(r()->error(), "12:34 error: index attribute must only be used with @location(0)");
 }
 
+class DualSourceBlendingExtensionTestWithParams : public ResolverTestWithParam<int> {
+  public:
+    DualSourceBlendingExtensionTestWithParams() {
+        Enable(core::Extension::kChromiumInternalDualSourceBlending);
+    }
+};
+
+// Rendering to multiple render targets while using dual source blending should fail.
+TEST_P(DualSourceBlendingExtensionTestWithParams, MultipleRenderTargetsNotAllowed) {
+    Structure("Output",
+              Vector{
+                  Member("a", ty.vec4<f32>(), Vector{Location(0_a), Index(0_a)}),
+                  Member("b", ty.vec4<f32>(), Vector{Location(0_a), Index(1_a)}),
+                  Member("c", ty.vec4<f32>(), Vector{Location(Source{{12, 34}}, AInt(GetParam()))}),
+              });
+
+    EXPECT_FALSE(r()->Resolve());
+    StringStream err;
+    err << "12:34 error: Multiple render targets are not allowed when using dual source blending. "
+           "The output @location("
+        << GetParam() << ") is not allowed as a render target.";
+    EXPECT_EQ(r()->error(), err.str());
+}
+
+INSTANTIATE_TEST_SUITE_P(DualSourceBlendingExtensionTests,
+                         DualSourceBlendingExtensionTestWithParams,
+                         testing::Values(1, 2, 3, 4, 5, 6, 7));
+
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index 5e39cad..ab50d71 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -2125,6 +2125,7 @@
         return false;
     }
 
+    auto has_index = false;
     Hashset<std::pair<uint32_t, uint32_t>, 8> locationsAndIndexes;
     for (auto* member : str->Members()) {
         if (auto* r = member->Type()->As<core::type::Array>()) {
@@ -2170,6 +2171,7 @@
                 },
                 [&](const ast::IndexAttribute* index) {
                     index_attribute = index;
+                    has_index = true;
                     return IndexAttribute(index, stage);
                 },
                 [&](const ast::BuiltinAttribute* builtin_attr) {
@@ -2242,6 +2244,15 @@
                 index = member->Attributes().index.value();
             }
             uint32_t location = member->Attributes().location.value();
+            if (has_index && location != 0) {
+                StringStream err;
+                err << "Multiple render targets are not allowed when using dual source blending. "
+                       "The output @location("
+                    << location << ") is not allowed as a render target.";
+                AddError(err.str(), location_attribute->source);
+                return false;
+            }
+
             std::pair<uint32_t, uint32_t> locationAndIndex(location, index);
             if (!locationsAndIndexes.Add(locationAndIndex)) {
                 StringStream err;