[spirv][ir] Convert spirv image types.

Add initial conversions of the `spirv.image` and `spirv.sampled_image`
types into their texture equivalents. This will be expanded as the
texture methods are implemented.

Bug: 391482238, 391482434
Change-Id: I4cacb9bf413571245a17038b51a0794f91f5c8e2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/240494
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/spirv/reader/lower/BUILD.bazel b/src/tint/lang/spirv/reader/lower/BUILD.bazel
index f5499f7..7b1610f 100644
--- a/src/tint/lang/spirv/reader/lower/BUILD.bazel
+++ b/src/tint/lang/spirv/reader/lower/BUILD.bazel
@@ -65,6 +65,7 @@
     "//src/tint/lang/spirv",
     "//src/tint/lang/spirv/intrinsic",
     "//src/tint/lang/spirv/ir",
+    "//src/tint/lang/spirv/type",
     "//src/tint/utils",
     "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
diff --git a/src/tint/lang/spirv/reader/lower/BUILD.cmake b/src/tint/lang/spirv/reader/lower/BUILD.cmake
index 5c9c9a3..2eeb9bf 100644
--- a/src/tint/lang/spirv/reader/lower/BUILD.cmake
+++ b/src/tint/lang/spirv/reader/lower/BUILD.cmake
@@ -64,6 +64,7 @@
   tint_lang_spirv
   tint_lang_spirv_intrinsic
   tint_lang_spirv_ir
+  tint_lang_spirv_type
   tint_utils
   tint_utils_containers
   tint_utils_diagnostic
diff --git a/src/tint/lang/spirv/reader/lower/BUILD.gn b/src/tint/lang/spirv/reader/lower/BUILD.gn
index 87c9217..31224fb 100644
--- a/src/tint/lang/spirv/reader/lower/BUILD.gn
+++ b/src/tint/lang/spirv/reader/lower/BUILD.gn
@@ -70,6 +70,7 @@
     "${tint_src_dir}/lang/spirv",
     "${tint_src_dir}/lang/spirv/intrinsic",
     "${tint_src_dir}/lang/spirv/ir",
+    "${tint_src_dir}/lang/spirv/type",
     "${tint_src_dir}/utils",
     "${tint_src_dir}/utils/containers",
     "${tint_src_dir}/utils/diagnostic",
diff --git a/src/tint/lang/spirv/reader/lower/texture.cc b/src/tint/lang/spirv/reader/lower/texture.cc
index 98afede..f8ba558 100644
--- a/src/tint/lang/spirv/reader/lower/texture.cc
+++ b/src/tint/lang/spirv/reader/lower/texture.cc
@@ -32,6 +32,9 @@
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/module.h"
 #include "src/tint/lang/core/ir/validator.h"
+#include "src/tint/lang/core/type/sampled_texture.h"
+#include "src/tint/lang/core/type/storage_texture.h"
+#include "src/tint/lang/spirv/type/image.h"
 
 namespace tint::spirv::reader::lower {
 namespace {
@@ -51,7 +54,74 @@
     core::type::Manager& ty{ir.Types()};
 
     /// Process the module.
-    void Process() {}
+    void Process() {
+        for (auto* inst : *ir.root_block) {
+            auto* var = inst->As<core::ir::Var>();
+            if (!var) {
+                continue;
+            }
+
+            auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+            TINT_ASSERT(ptr);
+
+            auto* type = ptr->UnwrapPtr();
+            if (!type->Is<spirv::type::Image>()) {
+                continue;
+            }
+
+            auto* new_ty = TypeFor(type);
+            var->Result()->SetType(ty.ptr(ptr->AddressSpace(), new_ty, ptr->Access()));
+
+            // TOOD(dsinclair): Replace var usages
+        }
+    }
+
+    const core::type::Type* TypeFor(const core::type::Type* src_ty) {
+        TINT_ASSERT(src_ty->Is<spirv::type::Image>());
+
+        if (auto* img = src_ty->As<spirv::type::Image>()) {
+            return TypeForImage(img);
+        }
+
+        TINT_UNREACHABLE();
+    }
+
+    core::type::TextureDimension ConvertDim(spirv::type::Dim dim, spirv::type::Arrayed arrayed) {
+        switch (dim) {
+            case spirv::type::Dim::kD1:
+                return core::type::TextureDimension::k1d;
+            case spirv::type::Dim::kD2:
+                return arrayed == spirv::type::Arrayed::kArrayed
+                           ? core::type::TextureDimension::k2dArray
+                           : core::type::TextureDimension::k2d;
+            case spirv::type::Dim::kD3:
+                return core::type::TextureDimension::k3d;
+            case spirv::type::Dim::kCube:
+                return arrayed == spirv::type::Arrayed::kArrayed
+                           ? core::type::TextureDimension::kCubeArray
+                           : core::type::TextureDimension::kCube;
+            default:
+                TINT_UNREACHABLE();
+        }
+    }
+
+    const core::type::Type* TypeForImage(const spirv::type::Image* img) {
+        if (img->GetDim() == spirv::type::Dim::kSubpassData) {
+            return ty.input_attachment(img->GetSampledType());
+        }
+
+        if (img->GetSampled() == spirv::type::Sampled::kReadWriteOpCompatible) {
+            return ty.storage_texture(ConvertDim(img->GetDim(), img->GetArrayed()),
+                                      img->GetTexelFormat(), img->GetAccess());
+        }
+
+        // TODO(dsinclair): Handle determining depth texture by usage
+        if (img->GetDepth() == spirv::type::Depth::kDepth) {
+            return ty.depth_texture(ConvertDim(img->GetDim(), img->GetArrayed()));
+        }
+        return ty.sampled_texture(ConvertDim(img->GetDim(), img->GetArrayed()),
+                                  img->GetSampledType());
+    }
 };
 
 }  // namespace
diff --git a/src/tint/lang/spirv/reader/lower/texture_test.cc b/src/tint/lang/spirv/reader/lower/texture_test.cc
index 33081ea..0843602 100644
--- a/src/tint/lang/spirv/reader/lower/texture_test.cc
+++ b/src/tint/lang/spirv/reader/lower/texture_test.cc
@@ -46,7 +46,7 @@
 using Multisampled = spirv::type::Multisampled;
 using Sampled = spirv::type::Sampled;
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_1d) {
+TEST_F(SpirvReader_TextureTest, Type_Image_1d) {
     b.Append(mod.root_block, [&] {
         auto* v = b.Var("wg", ty.ptr(handle,
                                      ty.Get<spirv::type::Image>(
@@ -75,7 +75,7 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_2d) {
+TEST_F(SpirvReader_TextureTest, Type_Image_2d) {
     b.Append(mod.root_block, [&] {
         auto* v = b.Var("wg", ty.ptr(handle,
                                      ty.Get<spirv::type::Image>(
@@ -104,7 +104,7 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_3d) {
+TEST_F(SpirvReader_TextureTest, Type_Image_3d) {
     b.Append(mod.root_block, [&] {
         auto* v = b.Var("wg", ty.ptr(handle,
                                      ty.Get<spirv::type::Image>(
@@ -133,7 +133,7 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_Cube) {
+TEST_F(SpirvReader_TextureTest, Type_Image_Cube) {
     b.Append(mod.root_block, [&] {
         auto* v =
             b.Var("wg", ty.ptr(handle,
@@ -163,7 +163,7 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_SubpassData) {
+TEST_F(SpirvReader_TextureTest, Type_Image_SubpassData) {
     b.Append(mod.root_block, [&] {
         auto* v = b.Var(
             "wg", ty.ptr(handle,
@@ -193,11 +193,11 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_Depth) {
+TEST_F(SpirvReader_TextureTest, Type_Image_Depth) {
     b.Append(mod.root_block, [&] {
         auto* v = b.Var("wg", ty.ptr(handle,
                                      ty.Get<spirv::type::Image>(
-                                         ty.f32(), Dim::kD1, Depth::kDepth, Arrayed::kNonArrayed,
+                                         ty.f32(), Dim::kD2, Depth::kDepth, Arrayed::kNonArrayed,
                                          Multisampled::kSingleSampled, Sampled::kSamplingCompatible,
                                          core::TexelFormat::kUndefined, core::Access::kRead),
                                      read));
@@ -206,7 +206,7 @@
 
     auto* src = R"(
 $B1: {  # root
-  %wg:ptr<handle, spirv.image<f32, 1d, depth, non_arrayed, single_sampled, sampling_compatible, undefined, read>, read> = var undef @binding_point(1, 2)
+  %wg:ptr<handle, spirv.image<f32, 2d, depth, non_arrayed, single_sampled, sampling_compatible, undefined, read>, read> = var undef @binding_point(1, 2)
 }
 
 )";
@@ -215,7 +215,7 @@
 
     auto* expect = R"(
 $B1: {  # root
-  %wg:ptr<handle, texture_depth_1d<f32>, read> = var undef @binding_point(1, 2)
+  %wg:ptr<handle, texture_depth_2d, read> = var undef @binding_point(1, 2)
 }
 
 )";
@@ -251,7 +251,7 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_Arrayed) {
+TEST_F(SpirvReader_TextureTest, Type_Image_Arrayed) {
     b.Append(mod.root_block, [&] {
         auto* v = b.Var("wg", ty.ptr(handle,
                                      ty.Get<spirv::type::Image>(
@@ -280,21 +280,21 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_RW_Ops) {
+TEST_F(SpirvReader_TextureTest, Type_Image_RW_Ops) {
     b.Append(mod.root_block, [&] {
         auto* v =
             b.Var("wg", ty.ptr(handle,
                                ty.Get<spirv::type::Image>(
                                    ty.f32(), Dim::kD1, Depth::kNotDepth, Arrayed::kNonArrayed,
                                    Multisampled::kSingleSampled, Sampled::kReadWriteOpCompatible,
-                                   core::TexelFormat::kUndefined, core::Access::kRead),
+                                   core::TexelFormat::kRg32Float, core::Access::kRead),
                                read));
         v->SetBindingPoint(1, 2);
     });
 
     auto* src = R"(
 $B1: {  # root
-  %wg:ptr<handle, spirv.image<f32, 1d, not_depth, non_arrayed, single_sampled, rw_op_compatbile, undefined, read>, read> = var undef @binding_point(1, 2)
+  %wg:ptr<handle, spirv.image<f32, 1d, not_depth, non_arrayed, single_sampled, rw_op_compatible, rg32float, read>, read> = var undef @binding_point(1, 2)
 }
 
 )";
@@ -303,14 +303,14 @@
 
     auto* expect = R"(
 $B1: {  # root
-  %wg:ptr<handle, texture_1d<f32>, read> = var undef @binding_point(1, 2)
+  %wg:ptr<handle, texture_storage_1d<rg32float, read>, read> = var undef @binding_point(1, 2)
 }
 
 )";
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_Image_TexelFormat) {
+TEST_F(SpirvReader_TextureTest, Type_Image_TexelFormat) {
     b.Append(mod.root_block, [&] {
         auto* v = b.Var("wg", ty.ptr(handle,
                                      ty.Get<spirv::type::Image>(
@@ -323,7 +323,7 @@
 
     auto* src = R"(
 $B1: {  # root
-  %wg:ptr<handle, spirv.image<f32, 2d, not_depth, non_arrayed, single_sampled, sampling_compatible, undefined, read>, read> = var undef @binding_point(1, 2)
+  %wg:ptr<handle, spirv.image<f32, 1d, not_depth, non_arrayed, single_sampled, sampling_compatible, rg32float, read>, read> = var undef @binding_point(1, 2)
 }
 
 )";
@@ -332,37 +332,7 @@
 
     auto* expect = R"(
 $B1: {  # root
-  %wg:ptr<handle, texture_storage_1d<rg32float, read>, read_write> = var undef @binding_point(1, 2)
-}
-
-)";
-    ASSERT_EQ(expect, str());
-}
-
-TEST_F(SpirvReader_TextureTest, DISABLED_Type_SampledImage) {
-    b.Append(mod.root_block, [&] {
-        auto* v = b.Var("wg", ty.ptr(handle,
-                                     ty.Get<spirv::type::SampledImage>(ty.Get<spirv::type::Image>(
-                                         ty.f32(), Dim::kD1, Depth::kNotDepth, Arrayed::kNonArrayed,
-                                         Multisampled::kSingleSampled, Sampled::kSamplingCompatible,
-                                         core::TexelFormat::kRg32Float, core::Access::kRead)),
-                                     read));
-        v->SetBindingPoint(1, 2);
-    });
-
-    auto* src = R"(
-$B1: {  # root
-  %wg:ptr<handle, spirv.sampled_image<spirv.image<f32, 2d, not_depth, non_arrayed, single_sampled, sampling_compatible, undefined, read>>, read> = var undef @binding_point(1, 2)
-}
-
-)";
-    ASSERT_EQ(src, str());
-    Run(Texture);
-
-    auto* expect = R"(
-$B1: {  # root
-  %wg_1:ptr<handle, sampler, read> = var undef @binding_point(1, 2)
-  %wg:ptr<handle, texture_storage_1d<rg32float, read>, read> = var undef @binding_point(1, 2)
+  %wg:ptr<handle, texture_1d<f32>, read> = var undef @binding_point(1, 2)
 }
 
 )";
diff --git a/src/tint/lang/spirv/reader/parser/image_sampler_test.cc b/src/tint/lang/spirv/reader/parser/image_sampler_test.cc
index 905007d..0d3aaae 100644
--- a/src/tint/lang/spirv/reader/parser/image_sampler_test.cc
+++ b/src/tint/lang/spirv/reader/parser/image_sampler_test.cc
@@ -416,7 +416,8 @@
 )",
               R"(
 $B1: {  # root
-  %1:ptr<handle, spirv.sampled_image<spirv.image<f32, 1d, not_depth, non_arrayed, single_sampled, sampling_compatible, rg32float, read>>, read> = var undef @binding_point(1, 2)
+  %1:ptr<handle, sampler, read> = var undef @binding_point(1, 2)
+  %2:ptr<handle, spirv.image<f32, 1d, not_depth, non_arrayed, single_sampled, sampling_compatible, rg32float, read>, read> = var undef @binding_point(1, 2)
 }
 
 %main = @compute @workgroup_size(1u, 1u, 1u) func():void {
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index 8b3cde0..31e7f70 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -43,6 +43,7 @@
 TINT_BEGIN_DISABLE_WARNING(WEAK_VTABLES);
 TINT_BEGIN_DISABLE_WARNING(UNSAFE_BUFFER_USAGE);
 #include "source/opt/build_module.h"
+#include "source/opt/split_combined_image_sampler_pass.h"
 TINT_END_DISABLE_WARNING(UNSAFE_BUFFER_USAGE);
 TINT_END_DISABLE_WARNING(WEAK_VTABLES);
 TINT_END_DISABLE_WARNING(SIGN_CONVERSION);
@@ -89,6 +90,14 @@
             return Failure("failed to build the internal representation of the module");
         }
 
+        {
+            spvtools::opt::SplitCombinedImageSamplerPass pass;
+            auto status = pass.Run(spirv_context_.get());
+            if (status == spvtools::opt::Pass::Status::Failure) {
+                return Failure("failed to run SplitCombinedImageSamplerPass in SPIR-V opt");
+            }
+        }
+
         // Check for unsupported extensions.
         for (const auto& ext : spirv_context_->extensions()) {
             auto name = ext.GetOperand(0).AsString();
@@ -419,8 +428,8 @@
                                                        texel_format, access);
                 }
                 case spvtools::opt::analysis::Type::kSampledImage: {
-                    auto* sampled = type->AsSampledImage();
-                    return ty_.Get<spirv::type::SampledImage>(Type(sampled->image_type()));
+                    TINT_UNREACHABLE() << "OpTypeSampledImage should have been removed by the "
+                                          "SplitCombinedImageSamplerPass";
                 }
                 default: {
                     TINT_UNIMPLEMENTED() << "unhandled SPIR-V type: " << type->str();