[spirv-writer] Convert ast image format types to spv

Change-Id: I987e729a607e69294c472b7667eae82c7339a0df
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27640
Commit-Queue: Tomek Ponitka <tommek@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 52c9e50..f63a82e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -828,6 +828,7 @@
     "src/writer/spirv/builder_constructor_expression_test.cc",
     "src/writer/spirv/builder_discard_test.cc",
     "src/writer/spirv/builder_entry_point_test.cc",
+    "src/writer/spirv/builder_format_conversion_test.cc",
     "src/writer/spirv/builder_function_test.cc",
     "src/writer/spirv/builder_function_variable_test.cc",
     "src/writer/spirv/builder_global_variable_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 99ea14a..9e767ba 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -481,6 +481,7 @@
     writer/spirv/builder_constructor_expression_test.cc
     writer/spirv/builder_discard_test.cc
     writer/spirv/builder_entry_point_test.cc
+    writer/spirv/builder_format_conversion_test.cc
     writer/spirv/builder_function_test.cc
     writer/spirv/builder_function_variable_test.cc
     writer/spirv/builder_global_variable_test.cc
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index ec18b62..04076b1 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -2136,6 +2136,101 @@
   return SpvBuiltInMax;
 }
 
+SpvImageFormat Builder::convert_image_format_to_spv(
+    const ast::type::ImageFormat format) {
+  switch (format) {
+    case ast::type::ImageFormat::kR8Unorm:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR8;
+    case ast::type::ImageFormat::kR8Snorm:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR8Snorm;
+    case ast::type::ImageFormat::kR8Uint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR8ui;
+    case ast::type::ImageFormat::kR8Sint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR8i;
+    case ast::type::ImageFormat::kR16Uint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR16ui;
+    case ast::type::ImageFormat::kR16Sint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR16i;
+    case ast::type::ImageFormat::kR16Float:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR16f;
+    case ast::type::ImageFormat::kRg8Unorm:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg8;
+    case ast::type::ImageFormat::kRg8Snorm:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg8Snorm;
+    case ast::type::ImageFormat::kRg8Uint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg8ui;
+    case ast::type::ImageFormat::kRg8Sint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg8i;
+    case ast::type::ImageFormat::kR32Uint:
+      return SpvImageFormatR32ui;
+    case ast::type::ImageFormat::kR32Sint:
+      return SpvImageFormatR32i;
+    case ast::type::ImageFormat::kR32Float:
+      return SpvImageFormatR32f;
+    case ast::type::ImageFormat::kRg16Uint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg16ui;
+    case ast::type::ImageFormat::kRg16Sint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg16i;
+    case ast::type::ImageFormat::kRg16Float:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg16f;
+    case ast::type::ImageFormat::kRgba8Unorm:
+      return SpvImageFormatRgba8;
+    case ast::type::ImageFormat::kRgba8UnormSrgb:
+      return SpvImageFormatUnknown;
+    case ast::type::ImageFormat::kRgba8Snorm:
+      return SpvImageFormatRgba8Snorm;
+    case ast::type::ImageFormat::kRgba8Uint:
+      return SpvImageFormatRgba8ui;
+    case ast::type::ImageFormat::kRgba8Sint:
+      return SpvImageFormatRgba8i;
+    case ast::type::ImageFormat::kBgra8Unorm:
+      return SpvImageFormatUnknown;
+    case ast::type::ImageFormat::kBgra8UnormSrgb:
+      return SpvImageFormatUnknown;
+    case ast::type::ImageFormat::kRgb10A2Unorm:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRgb10A2;
+    case ast::type::ImageFormat::kRg11B10Float:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatR11fG11fB10f;
+    case ast::type::ImageFormat::kRg32Uint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg32ui;
+    case ast::type::ImageFormat::kRg32Sint:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg32i;
+    case ast::type::ImageFormat::kRg32Float:
+      push_capability(SpvCapabilityStorageImageExtendedFormats);
+      return SpvImageFormatRg32f;
+    case ast::type::ImageFormat::kRgba16Uint:
+      return SpvImageFormatRgba16ui;
+    case ast::type::ImageFormat::kRgba16Sint:
+      return SpvImageFormatRgba16i;
+    case ast::type::ImageFormat::kRgba16Float:
+      return SpvImageFormatRgba16f;
+    case ast::type::ImageFormat::kRgba32Uint:
+      return SpvImageFormatRgba32ui;
+    case ast::type::ImageFormat::kRgba32Sint:
+      return SpvImageFormatRgba32i;
+    case ast::type::ImageFormat::kRgba32Float:
+      return SpvImageFormatRgba32f;
+  }
+}
+
 }  // namespace spirv
 }  // namespace writer
 }  // namespace tint
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 92bc8af..869a92f 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -26,6 +26,7 @@
 #include "src/ast/literal.h"
 #include "src/ast/module.h"
 #include "src/ast/struct_member.h"
+#include "src/ast/type/storage_texture_type.h"
 #include "src/ast/type_constructor_expression.h"
 #include "src/scope_stack.h"
 #include "src/writer/spirv/function.h"
@@ -367,6 +368,12 @@
   /// @returns true if the vector was successfully generated
   bool GenerateVectorType(ast::type::VectorType* vec, const Operand& result);
 
+  // Converts ast image format to spv and pushes an appropriate capability.
+  // @returns SPIR-V image format type
+  // @param format AST image format type
+  SpvImageFormat convert_image_format_to_spv(
+      const ast::type::ImageFormat format);
+
  private:
   /// @returns an Operand with a new result ID in it. Increments the next_id_
   /// automatically.
diff --git a/src/writer/spirv/builder_format_conversion_test.cc b/src/writer/spirv/builder_format_conversion_test.cc
new file mode 100644
index 0000000..8e5b17a
--- /dev/null
+++ b/src/writer/spirv/builder_format_conversion_test.cc
@@ -0,0 +1,100 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest.h"
+#include "src/writer/spirv/builder.h"
+#include "src/writer/spirv/spv_dump.h"
+
+namespace tint {
+namespace writer {
+namespace spirv {
+namespace {
+
+struct TestData {
+  ast::type::ImageFormat ast_format;
+  SpvImageFormat_ spv_format;
+  bool extended_format = false;
+};
+inline std::ostream& operator<<(std::ostream& out, TestData data) {
+  out << data.ast_format;
+  return out;
+}
+using ImageFormatConversionTest = testing::TestWithParam<TestData>;
+
+TEST_P(ImageFormatConversionTest, ImageFormatConversion) {
+  auto param = GetParam();
+
+  ast::Module mod;
+  Builder b(&mod);
+
+  EXPECT_EQ(b.convert_image_format_to_spv(param.ast_format), param.spv_format);
+
+  if (param.extended_format) {
+    EXPECT_EQ(DumpInstructions(b.capabilities()),
+              R"(OpCapability StorageImageExtendedFormats
+)");
+  } else {
+    EXPECT_EQ(DumpInstructions(b.capabilities()), "");
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    BuilderTest,
+    ImageFormatConversionTest,
+    testing::Values(
+        TestData{ast::type::ImageFormat::kR8Unorm, SpvImageFormatR8, true},
+        TestData{ast::type::ImageFormat::kR8Snorm, SpvImageFormatR8Snorm, true},
+        TestData{ast::type::ImageFormat::kR8Uint, SpvImageFormatR8ui, true},
+        TestData{ast::type::ImageFormat::kR8Sint, SpvImageFormatR8i, true},
+        TestData{ast::type::ImageFormat::kR16Uint, SpvImageFormatR16ui, true},
+        TestData{ast::type::ImageFormat::kR16Sint, SpvImageFormatR16i, true},
+        TestData{ast::type::ImageFormat::kR16Float, SpvImageFormatR16f, true},
+        TestData{ast::type::ImageFormat::kRg8Unorm, SpvImageFormatRg8, true},
+        TestData{ast::type::ImageFormat::kRg8Snorm, SpvImageFormatRg8Snorm,
+                 true},
+        TestData{ast::type::ImageFormat::kRg8Uint, SpvImageFormatRg8ui, true},
+        TestData{ast::type::ImageFormat::kRg8Sint, SpvImageFormatRg8i, true},
+        TestData{ast::type::ImageFormat::kR32Uint, SpvImageFormatR32ui},
+        TestData{ast::type::ImageFormat::kR32Sint, SpvImageFormatR32i},
+        TestData{ast::type::ImageFormat::kR32Float, SpvImageFormatR32f},
+        TestData{ast::type::ImageFormat::kRg16Uint, SpvImageFormatRg16ui, true},
+        TestData{ast::type::ImageFormat::kRg16Sint, SpvImageFormatRg16i, true},
+        TestData{ast::type::ImageFormat::kRg16Float, SpvImageFormatRg16f, true},
+        TestData{ast::type::ImageFormat::kRgba8Unorm, SpvImageFormatRgba8},
+        TestData{ast::type::ImageFormat::kRgba8UnormSrgb,
+                 SpvImageFormatUnknown},
+        TestData{ast::type::ImageFormat::kRgba8Snorm, SpvImageFormatRgba8Snorm},
+        TestData{ast::type::ImageFormat::kRgba8Uint, SpvImageFormatRgba8ui},
+        TestData{ast::type::ImageFormat::kRgba8Sint, SpvImageFormatRgba8i},
+        TestData{ast::type::ImageFormat::kBgra8Unorm, SpvImageFormatUnknown},
+        TestData{ast::type::ImageFormat::kBgra8UnormSrgb,
+                 SpvImageFormatUnknown},
+        TestData{ast::type::ImageFormat::kRgb10A2Unorm, SpvImageFormatRgb10A2,
+                 true},
+        TestData{ast::type::ImageFormat::kRg11B10Float,
+                 SpvImageFormatR11fG11fB10f, true},
+        TestData{ast::type::ImageFormat::kRg32Uint, SpvImageFormatRg32ui, true},
+        TestData{ast::type::ImageFormat::kRg32Sint, SpvImageFormatRg32i, true},
+        TestData{ast::type::ImageFormat::kRg32Float, SpvImageFormatRg32f, true},
+        TestData{ast::type::ImageFormat::kRgba16Uint, SpvImageFormatRgba16ui},
+        TestData{ast::type::ImageFormat::kRgba16Sint, SpvImageFormatRgba16i},
+        TestData{ast::type::ImageFormat::kRgba16Float, SpvImageFormatRgba16f},
+        TestData{ast::type::ImageFormat::kRgba32Uint, SpvImageFormatRgba32ui},
+        TestData{ast::type::ImageFormat::kRgba32Sint, SpvImageFormatRgba32i},
+        TestData{ast::type::ImageFormat::kRgba32Float, SpvImageFormatRgba32f}));
+
+}  // namespace
+}  // namespace spirv
+}  // namespace writer
+}  // namespace tint