Validate RenderBundle texture formats

Adds validation and unittests that render bundle color attachments are
color renderable texture formats and depth/stencil attachments are
depth/stencil texture formats.

Bug: dawn:154
Change-Id: I4d062a82b32fb38820fb3ebeb4c265306aa7af24
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/10261
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/RenderBundleEncoder.cpp b/src/dawn_native/RenderBundleEncoder.cpp
index b4febef..03bf7cc 100644
--- a/src/dawn_native/RenderBundleEncoder.cpp
+++ b/src/dawn_native/RenderBundleEncoder.cpp
@@ -17,11 +17,37 @@
 #include "dawn_native/CommandValidation.h"
 #include "dawn_native/Commands.h"
 #include "dawn_native/Device.h"
+#include "dawn_native/Format.h"
 #include "dawn_native/RenderPipeline.h"
 #include "dawn_native/ValidationUtils_autogen.h"
 
 namespace dawn_native {
 
+    MaybeError ValidateColorAttachmentFormat(const DeviceBase* device,
+                                             dawn::TextureFormat textureFormat) {
+        DAWN_TRY(ValidateTextureFormat(textureFormat));
+        const Format* format = nullptr;
+        DAWN_TRY_ASSIGN(format, device->GetInternalFormat(textureFormat));
+        if (!format->IsColor() || !format->isRenderable) {
+            return DAWN_VALIDATION_ERROR(
+                "The color attachment texture format is not color renderable");
+        }
+        return {};
+    }
+
+    MaybeError ValidateDepthStencilAttachmentFormat(const DeviceBase* device,
+                                                    dawn::TextureFormat textureFormat) {
+        DAWN_TRY(ValidateTextureFormat(textureFormat));
+        const Format* format = nullptr;
+        DAWN_TRY_ASSIGN(format, device->GetInternalFormat(textureFormat));
+        if (!format->HasDepthOrStencil() || !format->isRenderable) {
+            return DAWN_VALIDATION_ERROR(
+                "The depth stencil attachment texture format is not a renderable depth/stencil "
+                "format");
+        }
+        return {};
+    }
+
     MaybeError ValidateRenderBundleEncoderDescriptor(
         const DeviceBase* device,
         const RenderBundleEncoderDescriptor* descriptor) {
@@ -38,11 +64,11 @@
         }
 
         for (uint32_t i = 0; i < descriptor->colorFormatsCount; ++i) {
-            DAWN_TRY(ValidateTextureFormat(descriptor->colorFormats[i]));
+            DAWN_TRY(ValidateColorAttachmentFormat(device, descriptor->colorFormats[i]));
         }
 
         if (descriptor->depthStencilFormat != nullptr) {
-            DAWN_TRY(ValidateTextureFormat(*descriptor->depthStencilFormat));
+            DAWN_TRY(ValidateDepthStencilAttachmentFormat(device, *descriptor->depthStencilFormat));
         }
 
         return {};
diff --git a/src/tests/unittests/validation/RenderBundleValidationTests.cpp b/src/tests/unittests/validation/RenderBundleValidationTests.cpp
index 6c38506..416405f 100644
--- a/src/tests/unittests/validation/RenderBundleValidationTests.cpp
+++ b/src/tests/unittests/validation/RenderBundleValidationTests.cpp
@@ -988,3 +988,33 @@
         ASSERT_DEVICE_ERROR(commandEncoder.Finish());
     }
 }
+
+// Test that color attachment texture formats must be color renderable and
+// depth stencil texture formats must be depth/stencil.
+TEST_F(RenderBundleValidationTest, TextureFormats) {
+    // Test that color formats are validated as color.
+    {
+        utils::ComboRenderBundleEncoderDescriptor desc = {};
+        desc.colorFormatsCount = 1;
+        desc.cColorFormats[0] = dawn::TextureFormat::Depth24PlusStencil8;
+        ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
+    }
+
+    // Test that color formats are validated as renderable.
+    {
+        utils::ComboRenderBundleEncoderDescriptor desc = {};
+        desc.colorFormatsCount = 1;
+        desc.cColorFormats[0] = dawn::TextureFormat::RGBA8Snorm;
+        ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
+    }
+
+    // Test that depth/stencil formats are validated as depth/stencil.
+    {
+        utils::ComboRenderBundleEncoderDescriptor desc = {};
+        desc.cDepthStencilFormat = dawn::TextureFormat::RGBA8Unorm;
+        desc.depthStencilFormat = &desc.cDepthStencilFormat;
+        ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
+    }
+
+    // Don't test non-renerable depth/stencil formats because we don't have any.
+}