[spirv-reader][ir] Add image sample explicit lod support.
Add support for `OpImageSampleExplicitLod`.
Bug: 407382643
Change-Id: Icafb17c1a045900bcfb0974c963a8025961ee149
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/242574
Auto-Submit: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
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 4b17c86..4c97a4d 100644
--- a/src/tint/lang/spirv/reader/lower/builtins.cc
+++ b/src/tint/lang/spirv/reader/lower/builtins.cc
@@ -241,6 +241,7 @@
case spirv::BuiltinFn::kImageQuerySamples:
case spirv::BuiltinFn::kImageQuerySize:
case spirv::BuiltinFn::kImageQuerySizeLod:
+ case spirv::BuiltinFn::kImageSampleExplicitLod:
case spirv::BuiltinFn::kImageSampleImplicitLod:
case spirv::BuiltinFn::kImageWrite:
// Ignore image methods, they'll be handled by the `Texture` transform.
diff --git a/src/tint/lang/spirv/reader/lower/texture.cc b/src/tint/lang/spirv/reader/lower/texture.cc
index e55efc8..20cbf35 100644
--- a/src/tint/lang/spirv/reader/lower/texture.cc
+++ b/src/tint/lang/spirv/reader/lower/texture.cc
@@ -108,6 +108,7 @@
case spirv::BuiltinFn::kImageQuerySamples:
case spirv::BuiltinFn::kImageQuerySize:
case spirv::BuiltinFn::kImageQuerySizeLod:
+ case spirv::BuiltinFn::kImageSampleExplicitLod:
case spirv::BuiltinFn::kImageSampleImplicitLod:
case spirv::BuiltinFn::kImageWrite:
builtin_worklist.Push(builtin);
@@ -136,8 +137,9 @@
case spirv::BuiltinFn::kImageQuerySizeLod:
ImageQuerySize(builtin);
break;
+ case spirv::BuiltinFn::kImageSampleExplicitLod:
case spirv::BuiltinFn::kImageSampleImplicitLod:
- ImageSampleImplicitLod(builtin);
+ ImageSample(builtin);
break;
case spirv::BuiltinFn::kImageWrite:
ImageWrite(builtin);
@@ -211,6 +213,12 @@
bool HasBias(uint32_t mask) {
return (mask & static_cast<uint32_t>(ImageOperandsMask::kBias)) != 0;
}
+ bool HasGrad(uint32_t mask) {
+ return (mask & static_cast<uint32_t>(ImageOperandsMask::kGrad)) != 0;
+ }
+ bool HasLod(uint32_t mask) {
+ return (mask & static_cast<uint32_t>(ImageOperandsMask::kLod)) != 0;
+ }
bool HasConstOffset(uint32_t mask) {
return (mask & static_cast<uint32_t>(ImageOperandsMask::kConstOffset)) != 0;
}
@@ -246,7 +254,7 @@
call->Destroy();
}
- void ImageSampleImplicitLod(spirv::ir::BuiltinCall* call) {
+ void ImageSample(spirv::ir::BuiltinCall* call) {
const auto& args = call->Args();
auto* sampled_image = args[0];
@@ -255,6 +263,8 @@
core::ir::Value* sampler = nullptr;
std::tie(tex, sampler) = GetTextureSampler(sampled_image);
+ auto* tex_ty = tex->Type();
+
auto* coords = args[1];
uint32_t operand_mask = GetOperandMask(args[2]);
@@ -264,18 +274,51 @@
new_args.Push(tex);
new_args.Push(sampler);
- ProcessCoords(tex->Type(), coords, new_args);
+ ProcessCoords(tex_ty, coords, new_args);
core::BuiltinFn fn = core::BuiltinFn::kTextureSample;
if (HasBias(operand_mask)) {
fn = core::BuiltinFn::kTextureSampleBias;
new_args.Push(args[idx++]);
}
+ if (HasLod(operand_mask)) {
+ fn = core::BuiltinFn::kTextureSampleLevel;
+
+ core::ir::Value* lod = args[idx++];
+
+ // Depth texture LOD in WGSL is i32/u32 but f32 in SPIR-V.
+ // Convert to i32
+ if (tex_ty->Is<core::type::DepthTexture>()) {
+ lod = b.Convert(ty.i32(), lod)->Result();
+ }
+ new_args.Push(lod);
+ }
+ if (HasGrad(operand_mask)) {
+ fn = core::BuiltinFn::kTextureSampleGrad;
+ new_args.Push(args[idx++]); // ddx
+ new_args.Push(args[idx++]); // ddy
+ }
if (HasConstOffset(operand_mask)) {
ProcessOffset(args[idx++], new_args);
}
- b.CallWithResult(call->DetachResult(), fn, new_args);
+ // Depth textures have a single value return in WGSL, but a vec4 in SPIR-V.
+ auto* call_ty = call->Result()->Type();
+ if (tex_ty->IsAnyOf<core::type::DepthTexture, core::type::DepthMultisampledTexture>()) {
+ call_ty = call_ty->DeepestElement();
+ }
+ auto* res = b.Call(call_ty, fn, new_args)->Result();
+
+ // Restore the vec4 result by padding with 0's.
+ if (call_ty != call->Result()->Type()) {
+ auto* vec = call->Result()->Type()->As<core::type::Vector>();
+ TINT_ASSERT(vec && vec->Width() == 4);
+
+ auto* z = b.Zero(call_ty);
+ res = b.Construct(call->Result()->Type(), res, z, z, z)->Result();
+ }
+
+ call->Result()->ReplaceAllUsesWith(res);
});
call->Destroy();
}
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index 7f7f38d..2c7669c 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -1408,8 +1408,11 @@
case spv::Op::OpImageQuerySizeLod:
EmitImageQuerySizeLod(inst);
break;
+ case spv::Op::OpImageSampleExplicitLod:
+ EmitImageSample(inst, spirv::BuiltinFn::kImageSampleExplicitLod);
+ break;
case spv::Op::OpImageSampleImplicitLod:
- EmitImageSampleImplicitLod(inst);
+ EmitImageSample(inst, spirv::BuiltinFn::kImageSampleImplicitLod);
break;
case spv::Op::OpImageWrite:
EmitImageWrite(inst);
@@ -1473,7 +1476,7 @@
inst.result_id());
}
- void EmitImageSampleImplicitLod(const spvtools::opt::Instruction& inst) {
+ void EmitImageSample(const spvtools::opt::Instruction& inst, spirv::BuiltinFn fn) {
auto sampled_image = Value(inst.GetSingleWordInOperand(0));
auto* coord = Value(inst.GetSingleWordInOperand(1));
@@ -1494,9 +1497,7 @@
args.Push(b_.Zero(ty_.u32()));
}
- Emit(b_.Call<spirv::ir::BuiltinCall>(Type(inst.type_id()),
- spirv::BuiltinFn::kImageSampleImplicitLod, args),
- inst.result_id());
+ Emit(b_.Call<spirv::ir::BuiltinCall>(Type(inst.type_id()), fn, args), inst.result_id());
}
void EmitImageWrite(const spvtools::opt::Instruction& inst) {
diff --git a/src/tint/lang/spirv/reader/texture_test.cc b/src/tint/lang/spirv/reader/texture_test.cc
index d763946..fe68abb 100644
--- a/src/tint/lang/spirv/reader/texture_test.cc
+++ b/src/tint/lang/spirv/reader/texture_test.cc
@@ -362,6 +362,71 @@
)");
}
+TEST_F(SpirvReaderTest, ImageSampleExplicitLod) {
+ EXPECT_IR(R"(
+ OpCapability Shader
+ OpCapability Sampled1D
+ OpMemoryModel Logical Simple
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpName %10 "wg"
+ OpDecorate %var_sampler DescriptorSet 0
+ OpDecorate %var_sampler Binding 0
+ OpDecorate %10 DescriptorSet 2
+ OpDecorate %10 Binding 0
+ %int = OpTypeInt 32 1
+ %float = OpTypeFloat 32
+ %v2int = OpTypeVector %int 2
+%v2float = OpTypeVector %float 2
+%v4float = OpTypeVector %float 4
+ %tex = OpTypeImage %float 2D 0 0 0 1 Unknown
+%ptr_tex = OpTypePointer UniformConstant %tex
+%sampled_img = OpTypeSampledImage %tex
+%sampler = OpTypeSampler
+%ptr_sampler = OpTypePointer UniformConstant %sampler
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+
+ %int_1 = OpConstant %int 1
+%float_1 = OpConstant %float 1
+%float_2 = OpConstant %float 2
+%coords2 = OpConstantComposite %v2float %float_1 %float_2
+
+%var_sampler = OpVariable %ptr_sampler UniformConstant
+ %10 = OpVariable %ptr_tex UniformConstant
+
+ %int_10 = OpConstant %int 10
+ %int_11 = OpConstant %int 11
+%offset2i = OpConstantComposite %v2int %int_10 %int_11
+
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %sam = OpLoad %sampler %var_sampler
+ %im = OpLoad %tex %10
+%sampled_image = OpSampledImage %sampled_img %im %sam
+ %result = OpImageSampleExplicitLod %v4float %sampled_image %coords2 Lod|ConstOffset %float_1 %offset2i
+ %r2 = OpFAdd %v4float %result %result
+ OpReturn
+ OpFunctionEnd
+ )",
+ R"(
+$B1: { # root
+ %1:ptr<handle, sampler, read> = var undef @binding_point(0, 0)
+ %wg:ptr<handle, texture_2d<f32>, read> = var undef @binding_point(2, 0)
+}
+
+%main = @fragment func():void {
+ $B2: {
+ %4:sampler = load %1
+ %5:texture_2d<f32> = load %wg
+ %6:vec4<f32> = textureSampleLevel %5, %4, vec2<f32>(1.0f, 2.0f), 1.0f, vec2<i32>(10i, 11i)
+ %7:vec4<f32> = add %6, %6
+ ret
+ }
+}
+)");
+}
+
TEST_F(SpirvReaderTest, ImageQuerySize) {
EXPECT_IR(R"(
OpCapability Shader
@@ -1060,7 +1125,7 @@
));
INSTANTIATE_TEST_SUITE_P(
- DISABLED_SpirvReaderTest_ImageSampleExplicitLod,
+ SpirvReaderTest_ImageSampleExplicitLod,
SamplerTest,
::testing::Values(
ImgData{
@@ -1068,14 +1133,19 @@
.spirv_type = "%float 2D 0 0 0 1 Unknown",
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords2 Lod %float_null",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn = "textureSampleLevel %4, %5, vec2<f32>(1.0f, 2.0f), 0.0f",
+ .wgsl_fn = R"(
+ %6:vec4<f32> = textureSampleLevel %5, %4, vec2<f32>(1.0f, 2.0f), 0.0f)",
},
ImgData{
.name = "2D Array Lod",
.spirv_type = "%float 2D 0 1 0 1 Unknown",
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords3 Lod %float_null",
.wgsl_type = "texture_2d_array<f32>",
- .wgsl_fn = "textureSampleLevel %4, %5, vec2<f32>(1.0f, 2.0f), 3i, 0.0f",
+ .wgsl_fn = R"(
+ %6:vec2<f32> = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), xy
+ %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
+ %8:i32 = convert %7
+ %9:vec4<f32> = textureSampleLevel %5, %4, %6, %8, 0.0f)",
},
ImgData{
.name = "2D Lod ConstOffset signed",
@@ -1083,8 +1153,8 @@
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords2 Lod|ConstOffset "
"%float_null %offset2i",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn =
- "textureSampleLevel %4, %5, vec2<f32>(1.0f, 2.0f), 0.0f, vec2<i32>(10i, 11i)",
+ .wgsl_fn = R"(
+ %6:vec4<f32> = textureSampleLevel %5, %4, vec2<f32>(1.0f, 2.0f), 0.0f, vec2<i32>(10i, 11i))",
},
ImgData{
.name = "2D lod ConstOffset unsigned",
@@ -1092,8 +1162,9 @@
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords2 Lod|ConstOffset "
"%float_null %offset2u",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn =
- "textureSampleLevel %4, %5, vec2<f32>(1.0f, 2.0f), 0.0f, vec2<u32>(20u, 21u)",
+ .wgsl_fn = R"(
+ %6:vec2<i32> = convert vec2<u32>(20u, 21u)
+ %7:vec4<f32> = textureSampleLevel %5, %4, vec2<f32>(1.0f, 2.0f), 0.0f, %6)",
},
ImgData{
.name = "2D Array lod ConstOffset",
@@ -1101,17 +1172,20 @@
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords3 Lod|ConstOffset "
"%float_null %offset2i",
.wgsl_type = "texture_2d_array<f32>",
- .wgsl_fn =
- "textureSampleLevel %4, %5, vec2<f32>(1.0f, 2.0f), 3i, 0.0f, vec2<i32>(10i, 11i)",
+ .wgsl_fn = R"(
+ %6:vec2<f32> = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), xy
+ %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
+ %8:i32 = convert %7
+ %9:vec4<f32> = textureSampleLevel %5, %4, %6, %8, 0.0f, vec2<i32>(10i, 11i))",
},
ImgData{
.name = "2D Grad",
.spirv_type = "%float 2D 0 0 0 1 Unknown",
.spirv_fn =
- "OpImageSampleExplicitLod %v4float %sampled_image %coords12 Grad %vf12 %vf21",
+ "OpImageSampleExplicitLod %v4float %sampled_image %coords2 Grad %vf12 %vf21",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn = "textureSampleGrad %4, %5, vec2<f32>(1.0f, 2.0f), vec2<f32>(1.0f, 2.0f), "
- "vec2<f32>(2.0f, 1.0)",
+ .wgsl_fn = R"(
+ %6:vec4<f32> = textureSampleGrad %5, %4, vec2<f32>(1.0f, 2.0f), vec2<f32>(1.0f, 2.0f), vec2<f32>(2.0f, 1.0f))",
},
ImgData{
.name = "2D Array Grad",
@@ -1119,8 +1193,11 @@
.spirv_fn =
"OpImageSampleExplicitLod %v4float %sampled_image %coords3 Grad %vf12 %vf21",
.wgsl_type = "texture_2d_array<f32>",
- .wgsl_fn = "textureSampleGrad %4, %5, vec2<f32>(1.0f, 2.0f), 3i, vec2<f32>(1.0f, "
- "2.0f), vec2<f32>(2.0f, 1.0f)",
+ .wgsl_fn = R"(
+ %6:vec2<f32> = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), xy
+ %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
+ %8:i32 = convert %7
+ %9:vec4<f32> = textureSampleGrad %5, %4, %6, %8, vec2<f32>(1.0f, 2.0f), vec2<f32>(2.0f, 1.0f))",
},
ImgData{
.name = "2D Grad ConstOffset signed",
@@ -1128,8 +1205,8 @@
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords2 "
"Grad|ConstOffset %vf12 %vf21 %offset2i",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn = "textureSampleGrad %4, %5, vec2<f32>(1.0f, 2.0f), vec2<f32>(1.0f, 2.0f), "
- "vec2<f32>(2.0f, 1.0), vec2<i32>(10i, 11i)",
+ .wgsl_fn = R"(
+ %6:vec4<f32> = textureSampleGrad %5, %4, vec2<f32>(1.0f, 2.0f), vec2<f32>(1.0f, 2.0f), vec2<f32>(2.0f, 1.0f), vec2<i32>(10i, 11i))",
},
ImgData{
.name = "2D Grad ConstOffset Unsigned",
@@ -1137,33 +1214,44 @@
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords2 "
"Grad|ConstOffset %vf12 %vf21 %offset2u",
.wgsl_type = "texture_2d<f32>",
- .wgsl_fn = "textureSampleGrad %4, %5, vec2<f32>(1.0f, 2.0f), vec2<f32>(1.0f, 2.0f), "
- "vec2<f32>(2.0f, 1.0f), vec2<u32>(20u, 21u)",
+ .wgsl_fn = R"(
+ %6:vec2<i32> = convert vec2<u32>(20u, 21u)
+ %7:vec4<f32> = textureSampleGrad %5, %4, vec2<f32>(1.0f, 2.0f), vec2<f32>(1.0f, 2.0f), vec2<f32>(2.0f, 1.0f), %6)",
},
ImgData{
- .name = "2D Arrayed Grad ConstOffset",
+ .name = "2D Array Grad ConstOffset",
.spirv_type = "%float 2D 0 1 0 1 Unknown",
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords3 "
"Grad|ConstOffset %vf12 %vf21 %offset2i",
.wgsl_type = "texture_2d_array<f32>",
- .wgsl_fn = "textureSampleGrad %4, %5, vec2<f32>(1.0f, 2.0f), 3i, vec2<f32>(1.0f, "
- "2.0f), vec2<f32>(2.0f, 1.0f, vec2<i32>(10i, 11i)",
+ .wgsl_fn = R"(
+ %6:vec2<f32> = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), xy
+ %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
+ %8:i32 = convert %7
+ %9:vec4<f32> = textureSampleGrad %5, %4, %6, %8, vec2<f32>(1.0f, 2.0f), vec2<f32>(2.0f, 1.0f), vec2<i32>(10i, 11i))",
},
ImgData{
- .name = "2D arrayed Grad ConstOffset Unsigned",
+ .name = "2D Array Grad ConstOffset Unsigned",
.spirv_type = "%float 2D 0 1 0 1 Unknown",
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %coords3 "
"Grad|ConstOffset %vf12 %vf21 %offset2u",
.wgsl_type = "texture_2d_array<f32>",
- .wgsl_fn = "textureSampleGrad %4, %5, vec2<f32>(1.0f, 2.0f), 3i, vec2<f32>(1.0f, 2.0), "
- "vec2<f32>(2.0f, 1.0f), vec2<u32>(20u, 21u)",
+ .wgsl_fn = R"(
+ %6:vec2<f32> = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), xy
+ %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
+ %8:i32 = convert %7
+ %9:vec2<i32> = convert vec2<u32>(20u, 21u)
+ %10:vec4<f32> = textureSampleGrad %5, %4, %6, %8, vec2<f32>(1.0f, 2.0f), vec2<f32>(2.0f, 1.0f), %9)",
},
ImgData{
.name = "2D Depth",
.spirv_type = "%float 2D 1 0 0 1 Unknown",
.spirv_fn = "OpImageSampleExplicitLod %v4float %sampled_image %vf12 Lod %float_1",
.wgsl_type = "texture_depth_2d",
- .wgsl_fn = "textureSampleLevel %4, %5, vec2<f23>(1.0f, 2.0f), 1i",
+ .wgsl_fn = R"(
+ %6:i32 = convert 1.0f
+ %7:f32 = textureSampleLevel %5, %4, vec2<f32>(1.0f, 2.0f), %6
+ %8:vec4<f32> = construct %7, 0.0f, 0.0f, 0.0f)",
}));
INSTANTIATE_TEST_SUITE_P(