[spirv-reader][ir] Add image query levels support.
Add support for `OpImageQueryLevels`.
Bug: 407375749
Change-Id: Ic24b5de0819418de8db81b945d7801cf36477586
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/242535
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/spirv/reader/lower/builtins.cc b/src/tint/lang/spirv/reader/lower/builtins.cc
index c12f1ea..ad9d2fd 100644
--- a/src/tint/lang/spirv/reader/lower/builtins.cc
+++ b/src/tint/lang/spirv/reader/lower/builtins.cc
@@ -237,6 +237,7 @@
break;
case spirv::BuiltinFn::kSampledImage:
case spirv::BuiltinFn::kImageGather:
+ case spirv::BuiltinFn::kImageQueryLevels:
case spirv::BuiltinFn::kImageQuerySize:
case spirv::BuiltinFn::kImageQuerySizeLod:
case spirv::BuiltinFn::kImageSampleImplicitLod:
diff --git a/src/tint/lang/spirv/reader/lower/texture.cc b/src/tint/lang/spirv/reader/lower/texture.cc
index ddb9c2b..f1660a7 100644
--- a/src/tint/lang/spirv/reader/lower/texture.cc
+++ b/src/tint/lang/spirv/reader/lower/texture.cc
@@ -104,6 +104,7 @@
switch (builtin->Func()) {
case spirv::BuiltinFn::kSampledImage:
case spirv::BuiltinFn::kImageGather:
+ case spirv::BuiltinFn::kImageQueryLevels:
case spirv::BuiltinFn::kImageQuerySize:
case spirv::BuiltinFn::kImageQuerySizeLod:
case spirv::BuiltinFn::kImageSampleImplicitLod:
@@ -124,6 +125,9 @@
case spirv::BuiltinFn::kImageGather:
ImageGather(builtin);
break;
+ case spirv::BuiltinFn::kImageQueryLevels:
+ ImageQueryLevels(builtin);
+ break;
case spirv::BuiltinFn::kImageQuerySize:
case spirv::BuiltinFn::kImageQuerySizeLod:
ImageQuerySize(builtin);
@@ -292,6 +296,25 @@
call->Destroy();
}
+ void ImageQueryLevels(spirv::ir::BuiltinCall* call) {
+ auto* image = call->Args()[0];
+
+ b.InsertBefore(call, [&] {
+ auto* type = call->Result()->Type();
+
+ // WGSL requires a `u32` result component where SPIR-V allows `i32` or `u32`
+ core::ir::Value* res = b.Call(ty.MatchWidth(ty.u32(), type),
+ core::BuiltinFn::kTextureNumLevels, Vector{image})
+ ->Result();
+ if (type->IsSignedIntegerScalarOrVector()) {
+ res = b.Convert(type, res)->Result();
+ }
+
+ call->Result()->ReplaceAllUsesWith(res);
+ });
+ call->Destroy();
+ }
+
void ImageQuerySize(spirv::ir::BuiltinCall* call) {
auto* image = call->Args()[0];
@@ -301,8 +324,7 @@
b.InsertBefore(call, [&] {
auto* type = call->Result()->Type();
- // WGSL requires a `u32` result component where SPIR-V allows
- // `i32` or `u32`
+ // WGSL requires a `u32` result component where SPIR-V allows `i32` or `u32`
auto* wgsl_type = ty.MatchWidth(ty.u32(), type);
// A SPIR-V OpImageQuery will return the array `element` entry with
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index e843c4a..47d7beb 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -1396,8 +1396,11 @@
case spv::Op::OpImageGather:
EmitImageGather(inst);
break;
+ case spv::Op::OpImageQueryLevels:
+ EmitImageQuery(inst, spirv::BuiltinFn::kImageQueryLevels);
+ break;
case spv::Op::OpImageQuerySize:
- EmitImageQuerySize(inst);
+ EmitImageQuery(inst, spirv::BuiltinFn::kImageQuerySize);
break;
case spv::Op::OpImageQuerySizeLod:
EmitImageQuerySizeLod(inst);
@@ -1534,12 +1537,11 @@
inst.result_id());
}
- void EmitImageQuerySize(const spvtools::opt::Instruction& inst) {
+ void EmitImageQuery(const spvtools::opt::Instruction& inst, spirv::BuiltinFn fn) {
auto* image = Value(inst.GetSingleWordInOperand(0));
auto* ty = Type(inst.type_id());
- Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(ty, spirv::BuiltinFn::kImageQuerySize,
- Vector{ty->DeepestElement()}, image),
+ Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(ty, fn, Vector{ty->DeepestElement()}, image),
inst.result_id());
}
diff --git a/src/tint/lang/spirv/reader/texture_test.cc b/src/tint/lang/spirv/reader/texture_test.cc
index 362aa36..7f48799 100644
--- a/src/tint/lang/spirv/reader/texture_test.cc
+++ b/src/tint/lang/spirv/reader/texture_test.cc
@@ -407,6 +407,51 @@
)");
}
+TEST_F(SpirvReaderTest, ImageQueryLevels) {
+ EXPECT_IR(R"(
+ OpCapability Shader
+ OpCapability Sampled1D
+ OpCapability ImageQuery
+ OpMemoryModel Logical Simple
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpName %wg "wg"
+ OpDecorate %wg DescriptorSet 2
+ OpDecorate %wg Binding 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %tex = OpTypeImage %float 1D 0 0 0 1 R32f
+%ptr_tex = OpTypePointer UniformConstant %tex
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+
+ %wg = OpVariable %ptr_tex UniformConstant
+
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %im = OpLoad %tex %wg
+ %result = OpImageQueryLevels %int %im
+ %r2 = OpIAdd %int %result %result
+ OpReturn
+ OpFunctionEnd
+ )",
+ R"(
+$B1: { # root
+ %wg:ptr<handle, texture_1d<f32>, read> = var undef @binding_point(2, 0)
+}
+
+%main = @fragment func():void {
+ $B2: {
+ %3:texture_1d<f32> = load %wg
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4
+ %6:i32 = add %5, %5
+ ret
+ }
+}
+)");
+}
+
TEST_F(SpirvReaderTest, ImageQuerySizeLod) {
EXPECT_IR(R"(
OpCapability Shader
@@ -2110,88 +2155,107 @@
::testing::Values(ImgData{
.name = "1D",
.spirv_type = "%float 1D 0 0 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQuerySizeLod %uint %im %int_1\n",
+ .spirv_fn = "%99 = OpImageQuerySizeLod %uint %im %int_1",
.wgsl_type = "texture_1d<f32>",
.wgsl_fn = R"(
%4:u32 = textureDimensions %3, 1i)",
}));
-INSTANTIATE_TEST_SUITE_P(DISABLED_SpirvReaderTest_ImageQueryLevels_SignedResult,
+INSTANTIATE_TEST_SUITE_P(SpirvReaderTest_ImageQueryLevels_SignedResult,
SampledImageAccessTest,
::testing::Values(
ImgData{
.name = "2D",
.spirv_type = "%float 2D 0 0 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "2D array",
.spirv_type = "%float 2D 0 1 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_2d_array<f32>",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "3D",
.spirv_type = "%float 3D 0 0 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_3d<f32>",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "Cube",
.spirv_type = "%float Cube 0 0 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_cube<f32>",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "Cube array",
.spirv_type = "%float Cube 0 1 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_cube_array<f32>",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "depth 2d",
.spirv_type = "%float 2D 1 0 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_depth_2d",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "depth 2d array",
.spirv_type = "%float 2D 1 1 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_depth_2d_array",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "depth cube",
.spirv_type = "%float Cube 1 0 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_depth_cube",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
},
ImgData{
.name = "depth cube array",
.spirv_type = "%float Cube 1 1 0 1 Unknown",
- .spirv_fn = "%99 = OpImageQueryLevels %int %im\n",
+ .spirv_fn = "%99 = OpImageQueryLevels %int %im",
.wgsl_type = "texture_depth_cube_array",
- .wgsl_fn = "let x_99 = i32(textureNumLevels(x_20))",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3
+ %5:i32 = convert %4)",
}));
// Spot check that a value conversion is inserted when SPIR-V asks for an unsigned int result.
-INSTANTIATE_TEST_SUITE_P(DISABLED_SpirvReaderTest_ImageQueryLevels_UnsignedResult,
+INSTANTIATE_TEST_SUITE_P(SpirvReaderTest_ImageQueryLevels_UnsignedResult,
SampledImageAccessTest,
::testing::Values(ImgData{
.name = "2D",
.spirv_type = "%float 2D 0 0 0 1 Unknown",
.spirv_fn = "%99 = OpImageQueryLevels %uint %im\n",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn = "let x_99 = textureNumLevels(x_20)",
+ .wgsl_fn = R"(
+ %4:u32 = textureNumLevels %3)",
}));
using MultiSampledImageAccessTest = SpirvReaderTestWithParam<ImgData>;