[ir][spirv-writer] Handle texture sample builtins
Use the BuiltinPolyfillSpirv transform to replace texture sample
builtins with calls to SPIR-V intrinsic functions that will create the
`OpSampledImage` and then execute an `OpImageSample*` instruction.
A `LiteralOperand` subclass of `ir::Constant` is used to represent the
literal 'image operands' operand, and a `SampledImage` subclass of
`type::Type` is used to represent the `OpSampledImage` type.
Bug: tint:1906
Change-Id: Id3fd166f1cf5772fd75aed5cbeb8c3c02ea65197
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/141230
Reviewed-by: Ben Clayton <bclayton@google.com>
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir.cc b/src/tint/writer/spirv/ir/generator_impl_ir.cc
index 024aa59..479cbd9 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir.cc
@@ -147,6 +147,15 @@
return s;
},
+ // Dedup a SampledImage if its underlying image will be deduped.
+ [&](const ir::transform::BuiltinPolyfillSpirv::SampledImage* si) -> const type::Type* {
+ auto* img = DedupType(si->Image(), types);
+ if (img != si->Image()) {
+ return types.Get<ir::transform::BuiltinPolyfillSpirv::SampledImage>(img);
+ }
+ return si;
+ },
+
[&](Default) { return ty; });
}
@@ -236,6 +245,11 @@
}
uint32_t GeneratorImplIr::Constant(ir::Constant* constant) {
+ // If it is a literal operand, just return the value.
+ if (auto* literal = constant->As<ir::transform::BuiltinPolyfillSpirv::LiteralOperand>()) {
+ return literal->Value()->ValueAs<uint32_t>();
+ }
+
auto id = Constant(constant->Value());
// Set the name for the SPIR-V result ID if provided in the module.
@@ -375,6 +389,9 @@
[&](const type::Struct* str) { EmitStructType(id, str, addrspace); },
[&](const type::Texture* tex) { EmitTextureType(id, tex); },
[&](const type::Sampler*) { module_.PushType(spv::Op::OpTypeSampler, {id}); },
+ [&](const ir::transform::BuiltinPolyfillSpirv::SampledImage* s) {
+ module_.PushType(spv::Op::OpTypeSampledImage, {id, Type(s->Image())});
+ },
[&](Default) {
TINT_ICE(Writer, diagnostics_) << "unhandled type: " << ty->FriendlyName();
});
@@ -1403,6 +1420,21 @@
case ir::IntrinsicCall::Kind::kSpirvSelect:
op = spv::Op::OpSelect;
break;
+ case ir::IntrinsicCall::Kind::kSpirvSampledImage:
+ op = spv::Op::OpSampledImage;
+ break;
+ case ir::IntrinsicCall::Kind::kSpirvImageSampleImplicitLod:
+ op = spv::Op::OpImageSampleImplicitLod;
+ break;
+ case ir::IntrinsicCall::Kind::kSpirvImageSampleExplicitLod:
+ op = spv::Op::OpImageSampleExplicitLod;
+ break;
+ case ir::IntrinsicCall::Kind::kSpirvImageSampleDrefImplicitLod:
+ op = spv::Op::OpImageSampleDrefImplicitLod;
+ break;
+ case ir::IntrinsicCall::Kind::kSpirvImageSampleDrefExplicitLod:
+ op = spv::Op::OpImageSampleDrefExplicitLod;
+ break;
}
OperandList operands = {Type(call->Result()->Type()), id};
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_texture_builtin_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_texture_builtin_test.cc
new file mode 100644
index 0000000..90711e7
--- /dev/null
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_texture_builtin_test.cc
@@ -0,0 +1,597 @@
+// Copyright 2023 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 "src/tint/writer/spirv/ir/test_helper_ir.h"
+
+#include "src/tint/builtin/function.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::writer::spirv {
+namespace {
+
+/// An additional argument to a texture builtin.
+struct Arg {
+ /// The argument name.
+ const char* name;
+ /// The vector width of the argument (1 means scalar).
+ uint32_t width;
+ /// The element type of the argument.
+ TestElementType type;
+};
+
+/// A parameterized texture builtin function test case.
+struct TextureBuiltinTestCase {
+ /// The builtin function.
+ enum builtin::Function function;
+ /// The builtin function arguments.
+ utils::Vector<Arg, 4> optional_args;
+ /// The expected SPIR-V instruction string for the texture call.
+ const char* texture_call;
+};
+
+std::string PrintCase(testing::TestParamInfo<TextureBuiltinTestCase> cc) {
+ utils::StringStream ss;
+ ss << cc.param.function;
+ for (const auto& arg : cc.param.optional_args) {
+ ss << "_" << arg.name;
+ }
+ return ss.str();
+}
+
+class TextureBuiltinTest : public SpvGeneratorImplTestWithParam<TextureBuiltinTestCase> {
+ protected:
+ void Run(const type::Texture* texture_ty,
+ const type::Sampler* sampler_ty,
+ const type::Type* coord_ty,
+ const type::Type* return_ty) {
+ auto params = GetParam();
+
+ auto* t = b.FunctionParam("t", texture_ty);
+ auto* s = b.FunctionParam("s", sampler_ty);
+ auto* coord = b.FunctionParam("coords", coord_ty);
+ auto* func = b.Function("foo", return_ty);
+ func->SetParams({t, s, coord});
+
+ b.With(func->Block(), [&] {
+ utils::Vector<ir::Value*, 4> args = {t, s, coord};
+ uint32_t arg_value = 1;
+ for (const auto& arg : params.optional_args) {
+ auto* value = MakeScalarValue(arg.type, arg_value++);
+ if (arg.width > 1) {
+ value = b.Constant(mod.constant_values.Splat(ty.vec(value->Type(), arg.width),
+ value->Value(), arg.width));
+ }
+ args.Push(value);
+ mod.SetName(value, arg.name);
+ }
+ auto* result = b.Call(return_ty, params.function, std::move(args));
+ b.Return(func, result);
+ mod.SetName(result, "result");
+ });
+
+ ASSERT_TRUE(Generate()) << Error() << output_;
+ EXPECT_INST(params.texture_call);
+ }
+};
+
+using Texture1D = TextureBuiltinTest;
+TEST_P(Texture1D, Emit) {
+ Run(ty.Get<type::SampledTexture>(type::TextureDimension::k1d, ty.f32()),
+ ty.sampler(), // sampler type
+ ty.f32(), // coord type
+ ty.vec4<f32>() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+}
+INSTANTIATE_TEST_SUITE_P(SpvGeneratorImplTest,
+ Texture1D,
+ testing::Values(TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {},
+ "OpImageSampleImplicitLod %v4float %11 %coords None",
+ }),
+ PrintCase);
+
+using Texture2D = TextureBuiltinTest;
+TEST_P(Texture2D, Emit) {
+ Run(ty.Get<type::SampledTexture>(type::TextureDimension::k2d, ty.f32()),
+ ty.sampler(), // sampler type
+ ty.vec2<f32>(), // coord type
+ ty.vec4<f32>() // return type
+ );
+ EXPECT_INST("%12 = OpSampledImage %13 %t %s");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ Texture2D,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {},
+ "OpImageSampleImplicitLod %v4float %12 %coords None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"offset", 2, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %coords ConstOffset %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"bias", 1, kF32}},
+ "OpImageSampleImplicitLod %v4float %12 %coords Bias %bias",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"bias", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %coords Bias|ConstOffset %bias %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"ddx", 2, kF32}, {"ddy", 2, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Grad %ddx %ddy",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"ddx", 2, kF32}, {"ddy", 2, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Grad|ConstOffset %ddx %ddy %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Lod %lod",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Lod|ConstOffset %lod %offset",
+ }),
+ PrintCase);
+
+using Texture2DArray = TextureBuiltinTest;
+TEST_P(Texture2DArray, Emit) {
+ Run(ty.Get<type::SampledTexture>(type::TextureDimension::k2dArray, ty.f32()),
+ ty.sampler(), // sampler type
+ ty.vec2<f32>(), // coord type
+ ty.vec4<f32>() // return type
+ );
+ EXPECT_INST("%12 = OpSampledImage %13 %t %s");
+ EXPECT_INST("%14 = OpConvertSToF %float %array_idx");
+ EXPECT_INST("%18 = OpCompositeConstruct %v3float %coords %14");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ Texture2DArray,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"array_idx", 1, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %18 None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"array_idx", 1, kI32}, {"offset", 2, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %18 ConstOffset %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"array_idx", 1, kI32}, {"bias", 1, kF32}},
+ "OpImageSampleImplicitLod %v4float %12 %18 Bias %bias",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"array_idx", 1, kI32}, {"bias", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %18 Bias|ConstOffset %bias %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"array_idx", 1, kI32}, {"ddx", 2, kF32}, {"ddy", 2, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %18 Grad %ddx %ddy",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"array_idx", 1, kI32}, {"ddx", 2, kF32}, {"ddy", 2, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleExplicitLod %v4float %12 %18 Grad|ConstOffset %ddx %ddy %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"array_idx", 1, kI32}, {"lod", 1, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %18 Lod %lod",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"array_idx", 1, kI32}, {"lod", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleExplicitLod %v4float %12 %18 Lod|ConstOffset %lod %offset",
+ }),
+ PrintCase);
+
+using Texture3D = TextureBuiltinTest;
+TEST_P(Texture3D, Emit) {
+ Run(ty.Get<type::SampledTexture>(type::TextureDimension::k3d, ty.f32()),
+ ty.sampler(), // sampler type
+ ty.vec3<f32>(), // coord type
+ ty.vec4<f32>() // return type
+ );
+ EXPECT_INST("%12 = OpSampledImage %13 %t %s");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ Texture3D,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {},
+ "OpImageSampleImplicitLod %v4float %12 %coords None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"offset", 3, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %coords ConstOffset %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"bias", 1, kF32}},
+ "OpImageSampleImplicitLod %v4float %12 %coords Bias %bias",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"bias", 1, kF32}, {"offset", 3, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %coords Bias|ConstOffset %bias %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"ddx", 3, kF32}, {"ddy", 3, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Grad %ddx %ddy",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"ddx", 3, kF32}, {"ddy", 3, kF32}, {"offset", 3, kI32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Grad|ConstOffset %ddx %ddy %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Lod %lod",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kF32}, {"offset", 3, kI32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Lod|ConstOffset %lod %offset",
+ }),
+ PrintCase);
+
+using TextureCube = TextureBuiltinTest;
+TEST_P(TextureCube, Emit) {
+ Run(ty.Get<type::SampledTexture>(type::TextureDimension::kCube, ty.f32()),
+ ty.sampler(), // sampler type
+ ty.vec3<f32>(), // coord type
+ ty.vec4<f32>() // return type
+ );
+ EXPECT_INST("%12 = OpSampledImage %13 %t %s");
+}
+INSTANTIATE_TEST_SUITE_P(SpvGeneratorImplTest,
+ TextureCube,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {},
+ "OpImageSampleImplicitLod %v4float %12 %coords None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"bias", 1, kF32}},
+ "OpImageSampleImplicitLod %v4float %12 %coords Bias %bias",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"ddx", 3, kF32}, {"ddy", 3, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Grad %ddx %ddy",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %coords Lod %lod",
+ }),
+ PrintCase);
+
+using TextureCubeArray = TextureBuiltinTest;
+TEST_P(TextureCubeArray, Emit) {
+ Run(ty.Get<type::SampledTexture>(type::TextureDimension::kCubeArray, ty.f32()),
+ ty.sampler(), // sampler type
+ ty.vec3<f32>(), // coord type
+ ty.vec4<f32>() // return type
+ );
+ EXPECT_INST("%12 = OpSampledImage %13 %t %s");
+ EXPECT_INST("%14 = OpConvertSToF %float %array_idx");
+ EXPECT_INST("%17 = OpCompositeConstruct %v4float %coords %14");
+}
+INSTANTIATE_TEST_SUITE_P(SpvGeneratorImplTest,
+ TextureCubeArray,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"array_idx", 1, kI32}},
+ "OpImageSampleImplicitLod %v4float %12 %17 None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleBias,
+ {{"array_idx", 1, kI32}, {"bias", 1, kF32}},
+ "OpImageSampleImplicitLod %v4float %12 %17 Bias %bias",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleGrad,
+ {{"array_idx", 1, kI32}, {"ddx", 3, kF32}, {"ddy", 3, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %17 Grad %ddx %ddy",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"array_idx", 1, kI32}, {"lod", 1, kF32}},
+ "OpImageSampleExplicitLod %v4float %12 %17 Lod %lod",
+ }),
+ PrintCase);
+
+using TextureDepth2D = TextureBuiltinTest;
+TEST_P(TextureDepth2D, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::k2d),
+ ty.sampler(), // sampler type
+ ty.vec2<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+ EXPECT_INST("%result = OpCompositeExtract %float");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ TextureDepth2D,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {},
+ "OpImageSampleImplicitLod %v4float %11 %coords None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"offset", 2, kI32}},
+ "OpImageSampleImplicitLod %v4float %11 %coords ConstOffset %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kI32}},
+ "OpImageSampleExplicitLod %v4float %11 %coords Lod %13",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kI32}, {"offset", 2, kI32}},
+ "OpImageSampleExplicitLod %v4float %11 %coords Lod|ConstOffset %13 %offset",
+ }),
+ PrintCase);
+
+using TextureDepth2D_DepthComparison = TextureBuiltinTest;
+TEST_P(TextureDepth2D_DepthComparison, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::k2d),
+ ty.comparison_sampler(), // sampler type
+ ty.vec2<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ TextureDepth2D_DepthComparison,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompare,
+ {{"depth", 1, kF32}},
+ "OpImageSampleDrefImplicitLod %float %11 %coords %depth",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompare,
+ {{"depth", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleDrefImplicitLod %float %11 %coords %depth ConstOffset %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompareLevel,
+ {{"depth_l0", 1, kF32}},
+ "OpImageSampleDrefExplicitLod %float %11 %coords %depth_l0 Lod %float_0",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompareLevel,
+ {{"depth_l0", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleDrefExplicitLod %float %11 %coords %depth_l0 Lod|ConstOffset %float_0 "
+ "%offset",
+ }),
+ PrintCase);
+
+using TextureDepth2DArray = TextureBuiltinTest;
+TEST_P(TextureDepth2DArray, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::k2dArray),
+ ty.sampler(), // sampler type
+ ty.vec2<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+ EXPECT_INST("%13 = OpConvertSToF %float %array_idx");
+ EXPECT_INST("%17 = OpCompositeConstruct %v3float %coords %13");
+ EXPECT_INST("%result = OpCompositeExtract %float");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ TextureDepth2DArray,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"array_idx", 1, kI32}},
+ "OpImageSampleImplicitLod %v4float %11 %17 None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"array_idx", 1, kI32}, {"offset", 2, kI32}},
+ "OpImageSampleImplicitLod %v4float %11 %17 ConstOffset %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"array_idx", 1, kI32}, {"lod", 1, kI32}},
+ "OpImageSampleExplicitLod %v4float %11 %17 Lod %18",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"array_idx", 1, kI32}, {"lod", 1, kI32}, {"offset", 2, kI32}},
+ "OpImageSampleExplicitLod %v4float %11 %17 Lod|ConstOffset %18 %offset",
+ }),
+ PrintCase);
+
+using TextureDepth2DArray_DepthComparison = TextureBuiltinTest;
+TEST_P(TextureDepth2DArray_DepthComparison, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::k2dArray),
+ ty.comparison_sampler(), // sampler type
+ ty.vec2<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+ EXPECT_INST("%13 = OpConvertSToF %float %array_idx");
+ EXPECT_INST("%17 = OpCompositeConstruct %v3float %coords %13");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ TextureDepth2DArray_DepthComparison,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompare,
+ {{"array_idx", 1, kI32}, {"depth", 1, kF32}},
+ "OpImageSampleDrefImplicitLod %float %11 %17 %depth",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompare,
+ {{"array_idx", 1, kI32}, {"depth", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleDrefImplicitLod %float %11 %17 %depth ConstOffset %offset",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompareLevel,
+ {{"array_idx", 1, kI32}, {"depth_l0", 1, kF32}},
+ "OpImageSampleDrefExplicitLod %float %11 %17 %depth_l0 Lod %float_0",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompareLevel,
+ {{"array_idx", 1, kI32}, {"depth_l0", 1, kF32}, {"offset", 2, kI32}},
+ "OpImageSampleDrefExplicitLod %float %11 %17 %depth_l0 Lod|ConstOffset %float_0 "
+ "%offset",
+ }),
+ PrintCase);
+
+using TextureDepthCube = TextureBuiltinTest;
+TEST_P(TextureDepthCube, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::kCube),
+ ty.sampler(), // sampler type
+ ty.vec3<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+ EXPECT_INST("%result = OpCompositeExtract %float");
+}
+INSTANTIATE_TEST_SUITE_P(SpvGeneratorImplTest,
+ TextureDepthCube,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {},
+ "OpImageSampleImplicitLod %v4float %11 %coords None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"lod", 1, kI32}},
+ "OpImageSampleExplicitLod %v4float %11 %coords Lod %13",
+ }),
+ PrintCase);
+
+using TextureDepthCube_DepthComparison = TextureBuiltinTest;
+TEST_P(TextureDepthCube_DepthComparison, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::kCube),
+ ty.comparison_sampler(), // sampler typea
+ ty.vec3<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ TextureDepthCube_DepthComparison,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompare,
+ {{"depth", 1, kF32}},
+ "OpImageSampleDrefImplicitLod %float %11 %coords %depth",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompareLevel,
+ {{"depth_l0", 1, kF32}},
+ "OpImageSampleDrefExplicitLod %float %11 %coords %depth_l0 Lod %float_0",
+ }),
+ PrintCase);
+
+using TextureDepthCubeArray = TextureBuiltinTest;
+TEST_P(TextureDepthCubeArray, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::kCubeArray),
+ ty.sampler(), // sampler type
+ ty.vec3<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+ EXPECT_INST("%13 = OpConvertSToF %float %array_idx");
+ EXPECT_INST("%17 = OpCompositeConstruct %v4float %coords %13");
+ EXPECT_INST("%result = OpCompositeExtract %float");
+}
+INSTANTIATE_TEST_SUITE_P(SpvGeneratorImplTest,
+ TextureDepthCubeArray,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSample,
+ {{"array_idx", 1, kI32}},
+ "OpImageSampleImplicitLod %v4float %11 %17 None",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleLevel,
+ {{"array_idx", 1, kI32}, {"lod", 1, kI32}},
+ "OpImageSampleExplicitLod %v4float %11 %17 Lod %18",
+ }),
+ PrintCase);
+
+using TextureDepthCubeArray_DepthComparison = TextureBuiltinTest;
+TEST_P(TextureDepthCubeArray_DepthComparison, Emit) {
+ Run(ty.Get<type::DepthTexture>(type::TextureDimension::kCubeArray),
+ ty.comparison_sampler(), // sampler type
+ ty.vec3<f32>(), // coord type
+ ty.f32() // return type
+ );
+ EXPECT_INST("%11 = OpSampledImage %12 %t %s");
+ EXPECT_INST("%13 = OpConvertSToF %float %array_idx");
+ EXPECT_INST("%17 = OpCompositeConstruct %v4float %coords %13");
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpvGeneratorImplTest,
+ TextureDepthCubeArray_DepthComparison,
+ testing::Values(
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompare,
+ {{"array_idx", 1, kI32}, {"depth", 1, kF32}},
+ "OpImageSampleDrefImplicitLod %float %11 %17 %depth",
+ },
+ TextureBuiltinTestCase{
+ builtin::Function::kTextureSampleCompareLevel,
+ {{"array_idx", 1, kI32}, {"depth_l0", 1, kF32}},
+ "OpImageSampleDrefExplicitLod %float %11 %17 %depth_l0 Lod %float_0",
+ }),
+ PrintCase);
+
+} // namespace
+} // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/ir/test_helper_ir.h b/src/tint/writer/spirv/ir/test_helper_ir.h
index 3d86819..54af5ad 100644
--- a/src/tint/writer/spirv/ir/test_helper_ir.h
+++ b/src/tint/writer/spirv/ir/test_helper_ir.h
@@ -176,19 +176,20 @@
/// Helper to make a scalar value with the scalar type `type`.
/// @param type the element type
+ /// @param value the optional value to use
/// @returns the scalar value
- ir::Value* MakeScalarValue(TestElementType type) {
+ ir::Constant* MakeScalarValue(TestElementType type, uint32_t value = 1) {
switch (type) {
case kBool:
return b.Constant(true);
case kI32:
- return b.Constant(i32(1));
+ return b.Constant(i32(value));
case kU32:
- return b.Constant(u32(1));
+ return b.Constant(u32(value));
case kF32:
- return b.Constant(f32(1));
+ return b.Constant(f32(value));
case kF16:
- return b.Constant(f16(1));
+ return b.Constant(f16(value));
}
return nullptr;
}
@@ -196,7 +197,7 @@
/// Helper to make a vector value with an element type of `type`.
/// @param type the element type
/// @returns the vector value
- ir::Value* MakeVectorValue(TestElementType type) {
+ ir::Constant* MakeVectorValue(TestElementType type) {
switch (type) {
case kBool:
return b.Constant(mod.constant_values.Composite(