Better errors for incompatible attachment states

Now the message will report the details of both the expected and
incompatible attachment states, helping developers see what the source
of the error was.

Bug: dawn:563
Change-Id: I58eea166cb2da634f0295fb4660c982f96c62a2d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/84940
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Brandon Jones <bajones@chromium.org>
diff --git a/src/dawn/native/RenderEncoderBase.cpp b/src/dawn/native/RenderEncoderBase.cpp
index eeaf0e8..e6fd1a9 100644
--- a/src/dawn/native/RenderEncoderBase.cpp
+++ b/src/dawn/native/RenderEncoderBase.cpp
@@ -239,10 +239,12 @@
 
                     // TODO(dawn:563): More detail about why the states are incompatible would be
                     // nice.
-                    DAWN_INVALID_IF(
-                        pipeline->GetAttachmentState() != mAttachmentState.Get(),
-                        "Attachment state of %s is not compatible with the attachment state of %s",
-                        pipeline, this);
+                    DAWN_INVALID_IF(pipeline->GetAttachmentState() != mAttachmentState.Get(),
+                                    "Attachment state of %s is not compatible with %s.\n"
+                                    "%s expects an attachment state of %s.\n"
+                                    "%s has an attachment state of %s.",
+                                    pipeline, this, this, mAttachmentState.Get(), pipeline,
+                                    pipeline->GetAttachmentState());
 
                     DAWN_INVALID_IF(pipeline->WritesDepth() && mDepthReadOnly,
                                     "%s writes depth while %s's depthReadOnly is true", pipeline,
diff --git a/src/dawn/native/webgpu_absl_format.cpp b/src/dawn/native/webgpu_absl_format.cpp
index ec12220..e42ec89 100644
--- a/src/dawn/native/webgpu_absl_format.cpp
+++ b/src/dawn/native/webgpu_absl_format.cpp
@@ -14,6 +14,7 @@
 
 #include "dawn/native/webgpu_absl_format.h"
 
+#include "dawn/native/AttachmentState.h"
 #include "dawn/native/BindingInfo.h"
 #include "dawn/native/Device.h"
 #include "dawn/native/Format.h"
@@ -166,6 +167,48 @@
         return {true};
     }
 
+    absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+        const AttachmentState* value,
+        const absl::FormatConversionSpec& spec,
+        absl::FormatSink* s) {
+        if (value == nullptr) {
+            s->Append("[null]");
+            return {true};
+        }
+
+        s->Append("{ colorFormats: [");
+
+        ColorAttachmentIndex nextColorIndex(uint8_t(0));
+
+        bool needsComma = false;
+        for (ColorAttachmentIndex i : IterateBitSet(value->GetColorAttachmentsMask())) {
+            while (nextColorIndex < i) {
+                s->Append(absl::StrFormat("%s, ", wgpu::TextureFormat::Undefined));
+                nextColorIndex++;
+                needsComma = false;
+            }
+
+            if (needsComma) {
+                s->Append(", ");
+            }
+
+            s->Append(absl::StrFormat("%s", value->GetColorAttachmentFormat(i)));
+
+            nextColorIndex++;
+            needsComma = true;
+        }
+
+        s->Append("], ");
+
+        if (value->HasDepthStencilAttachment()) {
+            s->Append(absl::StrFormat("depthStencilFormat: %s, ", value->GetDepthStencilFormat()));
+        }
+
+        s->Append(absl::StrFormat("sampleCount: %u }", value->GetSampleCount()));
+
+        return {true};
+    }
+
     //
     // Enums
     //
diff --git a/src/dawn/native/webgpu_absl_format.h b/src/dawn/native/webgpu_absl_format.h
index 1872f47..ca7ddb5 100644
--- a/src/dawn/native/webgpu_absl_format.h
+++ b/src/dawn/native/webgpu_absl_format.h
@@ -73,6 +73,12 @@
         const absl::FormatConversionSpec& spec,
         absl::FormatSink* s);
 
+    class AttachmentState;
+    absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+        const AttachmentState* value,
+        const absl::FormatConversionSpec& spec,
+        absl::FormatSink* s);
+
     //
     // Enums
     //