[ir][spirv-writer] Handle storage texture loads
Map these to OpImageRead instead of OpImageFetch, and swizzle the
result when loading from a bgra8unorm texture.
Bug: tint:1906, tint:2007
Change-Id: I6752d2532aad71025da74a18c06c3f5716fb275c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/149922
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
index 1c414d7..d4fcbf2 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
@@ -149,7 +149,12 @@
swizzle->InsertBefore(call);
call->SetOperand(index, swizzle->Result());
} else if (call->Func() == core::Function::kTextureLoad) {
- TINT_ICE() << "unhandled bgra8unorm texture load";
+ // Swizzle the result of a `textureLoad()` builtin.
+ auto* swizzle =
+ b.Swizzle(call->Result()->Type(), nullptr, Vector{2u, 1u, 0u, 3u});
+ call->Result()->ReplaceAllUsesWith(swizzle->Result());
+ swizzle->InsertAfter(call);
+ swizzle->SetOperand(Swizzle::kObjectOperandOffset, call->Result());
}
},
[&](UserCall* call) {
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
index a7974d9..e8d19a3 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
@@ -604,5 +604,117 @@
EXPECT_EQ(expect, str());
}
+TEST_F(IR_Bgra8UnormPolyfillTest, TextureLoad) {
+ auto format = core::TexelFormat::kBgra8Unorm;
+ auto* texture_ty =
+ ty.Get<core::type::StorageTexture>(core::type::TextureDimension::k2d, format, read,
+ core::type::StorageTexture::SubtypeFor(format, ty));
+
+ auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
+ var->SetBindingPoint(1, 2);
+ b.RootBlock()->Append(var);
+
+ auto* func = b.Function("foo", ty.vec4<f32>());
+ auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
+ func->SetParams({coords});
+ b.Append(func->Block(), [&] {
+ auto* load = b.Load(var->Result());
+ auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load, coords);
+ b.Return(func, result);
+ mod.SetName(result, "result");
+ });
+
+ auto* src = R"(
+%b1 = block { # root
+ %texture:ptr<handle, texture_storage_2d<bgra8unorm, read>, read_write> = var @binding_point(1, 2)
+}
+
+%foo = func(%coords:vec2<u32>):vec4<f32> -> %b2 {
+ %b2 = block {
+ %4:texture_storage_2d<bgra8unorm, read> = load %texture
+ %result:vec4<f32> = textureLoad %4, %coords
+ ret %result
+ }
+}
+)";
+ auto* expect = R"(
+%b1 = block { # root
+ %texture:ptr<handle, texture_storage_2d<rgba8unorm, read>, read_write> = var @binding_point(1, 2)
+}
+
+%foo = func(%coords:vec2<u32>):vec4<f32> -> %b2 {
+ %b2 = block {
+ %4:texture_storage_2d<rgba8unorm, read> = load %texture
+ %result:vec4<f32> = textureLoad %4, %coords
+ %6:vec4<f32> = swizzle %result, zyxw
+ ret %6
+ }
+}
+)";
+
+ EXPECT_EQ(src, str());
+
+ Run(Bgra8UnormPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_Bgra8UnormPolyfillTest, TextureLoadAndStore) {
+ auto format = core::TexelFormat::kBgra8Unorm;
+ auto* texture_ty =
+ ty.Get<core::type::StorageTexture>(core::type::TextureDimension::k2d, format, read_write,
+ core::type::StorageTexture::SubtypeFor(format, ty));
+
+ auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
+ var->SetBindingPoint(1, 2);
+ b.RootBlock()->Append(var);
+
+ auto* func = b.Function("foo", ty.void_());
+ auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
+ func->SetParams({coords});
+ b.Append(func->Block(), [&] {
+ auto* load = b.Load(var->Result());
+ auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load, coords);
+ b.Call(ty.void_(), core::Function::kTextureStore, load, coords, result);
+ b.Return(func);
+ mod.SetName(result, "result");
+ });
+
+ auto* src = R"(
+%b1 = block { # root
+ %texture:ptr<handle, texture_storage_2d<bgra8unorm, read_write>, read_write> = var @binding_point(1, 2)
+}
+
+%foo = func(%coords:vec2<u32>):void -> %b2 {
+ %b2 = block {
+ %4:texture_storage_2d<bgra8unorm, read_write> = load %texture
+ %result:vec4<f32> = textureLoad %4, %coords
+ %6:void = textureStore %4, %coords, %result
+ ret
+ }
+}
+)";
+ auto* expect = R"(
+%b1 = block { # root
+ %texture:ptr<handle, texture_storage_2d<rgba8unorm, read_write>, read_write> = var @binding_point(1, 2)
+}
+
+%foo = func(%coords:vec2<u32>):void -> %b2 {
+ %b2 = block {
+ %4:texture_storage_2d<rgba8unorm, read_write> = load %texture
+ %result:vec4<f32> = textureLoad %4, %coords
+ %6:vec4<f32> = swizzle %result, zyxw
+ %7:vec4<f32> = swizzle %6, zyxw
+ %8:void = textureStore %4, %coords, %7
+ ret
+ }
+}
+)";
+
+ EXPECT_EQ(src, str());
+
+ Run(Bgra8UnormPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
} // namespace
} // namespace tint::core::ir::transform
diff --git a/src/tint/lang/spirv/ir/intrinsic.cc b/src/tint/lang/spirv/ir/intrinsic.cc
index 2b9c5f6..8933c06 100644
--- a/src/tint/lang/spirv/ir/intrinsic.cc
+++ b/src/tint/lang/spirv/ir/intrinsic.cc
@@ -89,6 +89,9 @@
if (str == "image_query_size_lod") {
return Intrinsic::kImageQuerySizeLod;
}
+ if (str == "image_read") {
+ return Intrinsic::kImageRead;
+ }
if (str == "image_sample_dref_explicit_lod") {
return Intrinsic::kImageSampleDrefExplicitLod;
}
@@ -157,6 +160,8 @@
return "image_query_size";
case Intrinsic::kImageQuerySizeLod:
return "image_query_size_lod";
+ case Intrinsic::kImageRead:
+ return "image_read";
case Intrinsic::kImageSampleDrefExplicitLod:
return "image_sample_dref_explicit_lod";
case Intrinsic::kImageSampleDrefImplicitLod:
diff --git a/src/tint/lang/spirv/ir/intrinsic.h b/src/tint/lang/spirv/ir/intrinsic.h
index c8288c3..2b5f906 100644
--- a/src/tint/lang/spirv/ir/intrinsic.h
+++ b/src/tint/lang/spirv/ir/intrinsic.h
@@ -54,6 +54,7 @@
kImageGather,
kImageQuerySize,
kImageQuerySizeLod,
+ kImageRead,
kImageSampleDrefExplicitLod,
kImageSampleDrefImplicitLod,
kImageSampleExplicitLod,
@@ -101,6 +102,7 @@
"image_gather",
"image_query_size",
"image_query_size_lod",
+ "image_read",
"image_sample_dref_explicit_lod",
"image_sample_dref_implicit_lod",
"image_sample_explicit_lod",
diff --git a/src/tint/lang/spirv/spirv.def b/src/tint/lang/spirv/spirv.def
index 1422511..11ee7ec 100644
--- a/src/tint/lang/spirv/spirv.def
+++ b/src/tint/lang/spirv/spirv.def
@@ -62,6 +62,7 @@
image_dref_gather
image_query_size
image_query_size_lod
+ image_read
image_sample_implicit_lod
image_sample_explicit_lod
image_sample_dref_implicit_lod
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index eaad696..e2c94fe 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -1633,6 +1633,9 @@
module_.PushCapability(SpvCapabilityImageQuery);
op = spv::Op::OpImageQuerySizeLod;
break;
+ case spirv::ir::Intrinsic::kImageRead:
+ op = spv::Op::OpImageRead;
+ break;
case spirv::ir::Intrinsic::kImageSampleImplicitLod:
op = spv::Op::OpImageSampleImplicitLod;
break;
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index 7616234..20290d5 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -673,8 +673,11 @@
if (expects_scalar_result) {
result_ty = ty.vec4(result_ty);
}
- auto* texture_call = b.Call<spirv::ir::IntrinsicCall>(
- result_ty, spirv::ir::Intrinsic::kImageFetch, std::move(intrinsic_args));
+ auto intrinsic = texture_ty->Is<core::type::StorageTexture>()
+ ? spirv::ir::Intrinsic::kImageRead
+ : spirv::ir::Intrinsic::kImageFetch;
+ auto* texture_call =
+ b.Call<spirv::ir::IntrinsicCall>(result_ty, intrinsic, std::move(intrinsic_args));
texture_call->InsertBefore(builtin);
auto* result = texture_call->Result();