spirv-reader: support OpImageGather

Bug: tint:1336
Change-Id: I771b09e7568f1f022a316f2ba0bc72c03f735aa1
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/74800
Auto-Submit: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: David Neto <dneto@google.com>
This commit is contained in:
David Neto 2022-01-04 15:46:39 +00:00 committed by Tint LUCI CQ
parent f09a23a3f7
commit 7d88368c56
2 changed files with 186 additions and 26 deletions

View File

@ -494,8 +494,9 @@ bool IsSampledImageAccess(SpvOp opcode) {
} }
// @param opcode a SPIR-V opcode // @param opcode a SPIR-V opcode
// @returns true if the given instruction is an image sampling operation. // @returns true if the given instruction is an image sampling, gather,
bool IsImageSampling(SpvOp opcode) { // or gather-compare operation.
bool IsImageSamplingOrGatherOrDrefGather(SpvOp opcode) {
switch (opcode) { switch (opcode) {
case SpvOpImageSampleImplicitLod: case SpvOpImageSampleImplicitLod:
case SpvOpImageSampleExplicitLod: case SpvOpImageSampleExplicitLod:
@ -506,6 +507,8 @@ bool IsImageSampling(SpvOp opcode) {
case SpvOpImageSampleProjExplicitLod: case SpvOpImageSampleProjExplicitLod:
case SpvOpImageSampleProjDrefImplicitLod: case SpvOpImageSampleProjDrefImplicitLod:
case SpvOpImageSampleProjDrefExplicitLod: case SpvOpImageSampleProjDrefExplicitLod:
case SpvOpImageGather:
case SpvOpImageDrefGather:
return true; return true;
default: default:
break; break;
@ -5247,6 +5250,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
} }
params.push_back(GetImageExpression(inst)); params.push_back(GetImageExpression(inst));
// Form the sampler operand, if needed.
if (IsSampledImageAccess(opcode)) { if (IsSampledImageAccess(opcode)) {
// Form the sampler operand. // Form the sampler operand.
if (auto* sampler = GetSamplerExpression(inst)) { if (auto* sampler = GetSamplerExpression(inst)) {
@ -5256,6 +5260,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
} }
} }
// Find the texture type.
const Pointer* texture_ptr_type = parser_impl_.GetTypeForHandleVar(*image); const Pointer* texture_ptr_type = parser_impl_.GetTypeForHandleVar(*image);
if (!texture_ptr_type) { if (!texture_ptr_type) {
return Fail(); return Fail();
@ -5309,8 +5314,16 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
} }
break; break;
case SpvOpImageGather: case SpvOpImageGather:
builtin_name = "textureGather";
if (!texture_type->Is<DepthTexture>()) {
// The explicit component is the *first* argument in WGSL.
params.insert(params.begin(), ToI32(MakeOperand(inst, arg_index)).expr);
}
// Skip over the component operand, even for depth textures.
arg_index++;
break;
case SpvOpImageDrefGather: case SpvOpImageDrefGather:
return Fail() << " image gather is not yet supported"; return Fail() << " image dref gather is not yet supported";
case SpvOpImageFetch: case SpvOpImageFetch:
case SpvOpImageRead: case SpvOpImageRead:
// Read a single texel from a sampled or storage image. // Read a single texel from a sampled or storage image.
@ -5407,8 +5420,9 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
} }
if (arg_index < num_args && if (arg_index < num_args &&
(image_operands_mask & SpvImageOperandsConstOffsetMask)) { (image_operands_mask & SpvImageOperandsConstOffsetMask)) {
if (!IsImageSampling(opcode)) { if (!IsImageSamplingOrGatherOrDrefGather(opcode)) {
return Fail() << "ConstOffset is only permitted for sampling operations: " return Fail() << "ConstOffset is only permitted for sampling, gather, or "
"depth-reference gather operations: "
<< inst.PrettyPrint(); << inst.PrettyPrint();
} }
switch (texture_type->dims) { switch (texture_type->dims) {

View File

@ -929,6 +929,7 @@ TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, Variable) {
EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage)); EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage));
EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage)); EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
// TODO(dneto): remove this. crbug.com/tint/1336
if (inst.find("Gather") != std::string::npos) { if (inst.find("Gather") != std::string::npos) {
// WGSL does not support Gather instructions yet. // WGSL does not support Gather instructions yet.
// So don't emit them as part of a "passing" corpus. // So don't emit them as part of a "passing" corpus.
@ -986,6 +987,7 @@ TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, FunctionParam) {
EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage)); EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage));
EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage)); EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
// TODO(dneto): remove this. crbug.com/tint/1336
if (inst.find("Gather") != std::string::npos) { if (inst.find("Gather") != std::string::npos) {
// WGSL does not support Gather instructions yet. // WGSL does not support Gather instructions yet.
// So don't emit them as part of a "passing" corpus. // So don't emit them as part of a "passing" corpus.
@ -1004,8 +1006,6 @@ INSTANTIATE_TEST_SUITE_P(
SpvParserHandleTest_RegisterHandleUsage_SampledImage, SpvParserHandleTest_RegisterHandleUsage_SampledImage,
::testing::Values( ::testing::Values(
// Test image gather even though WGSL doesn't support it yet.
// OpImageGather // OpImageGather
UsageImageAccessCase{"%result = OpImageGather " UsageImageAccessCase{"%result = OpImageGather "
"%v4float %sampled_image %coords %uint_1", "%v4float %sampled_image %coords %uint_1",
@ -1565,24 +1565,170 @@ TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage,
DISABLED_FunctionParam) {} DISABLED_FunctionParam) {}
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
DISABLED_ImageGather, ImageGather,
SpvParserHandleTest_SampledImageAccessTest, SpvParserHandleTest_SampledImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{ ::testing::ValuesIn(std::vector<ImageAccessCase>{
// TODO(dneto): OpImageGather // OpImageGather 2D
// TODO(dneto): OpImageGather with ConstOffset (signed and unsigned) ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
// TODO(dneto): OpImageGather with Offset (signed and unsigned) "%result = OpImageGather "
// TODO(dneto): OpImageGather with Offsets (signed and unsigned) "%v4float %sampled_image %coords12 %int_1",
})); R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_2d<f32>;)",
"textureGather(1, x_20, x_10, coords12)"},
// OpImageGather 2D ConstOffset signed
ImageAccessCase{
"%float 2D 0 0 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords12 %int_1 ConstOffset %offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_2d<f32>;)",
"textureGather(1, x_20, x_10, coords12, vec2<i32>(3, 4))"},
// OpImageGather 2D ConstOffset unsigned
ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords12 %int_1 ConstOffset "
"%u_offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_2d<f32>;)",
"textureGather(1, x_20, x_10, coords12, "
"vec2<i32>(vec2<u32>(3u, 4u)))"},
// OpImageGather 2D Array
ImageAccessCase{"%float 2D 0 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_2d_array<f32>;)",
"textureGather(1, x_20, x_10, coords123.xy, "
"i32(round(coords123.z)))"},
// OpImageGather 2D Array ConstOffset signed
ImageAccessCase{
"%float 2D 0 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1 ConstOffset %offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_2d_array<f32>;)",
"textureGather(1, x_20, x_10, coords123.xy, "
"i32(round(coords123.z)), vec2<i32>(3, 4))"},
// OpImageGather 2D Array ConstOffset unsigned
ImageAccessCase{"%float 2D 0 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1 ConstOffset "
"%u_offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_2d_array<f32>;)",
"textureGather(1, x_20, x_10, coords123.xy, "
"i32(round(coords123.z)), "
"vec2<i32>(vec2<u32>(3u, 4u)))"},
// OpImageGather Cube
ImageAccessCase{"%float Cube 0 0 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_cube<f32>;)",
"textureGather(1, x_20, x_10, coords123)"},
// OpImageGather Cube Array
ImageAccessCase{"%float Cube 0 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords1234 %int_1",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_cube_array<f32>;)",
"textureGather(1, x_20, x_10, coords1234.xyz, "
"i32(round(coords1234.w)))"},
// OpImageGather 2DDepth
ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords12 %int_1",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_2d;)",
"textureGather(x_20, x_10, coords12)"},
// OpImageGather 2DDepth ConstOffset signed
ImageAccessCase{
"%float 2D 1 0 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords12 %int_1 ConstOffset %offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_2d;)",
"textureGather(x_20, x_10, coords12, vec2<i32>(3, 4))"},
// OpImageGather 2DDepth ConstOffset unsigned
ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords12 %int_1 ConstOffset "
"%u_offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_2d;)",
"textureGather(x_20, x_10, coords12, "
"vec2<i32>(vec2<u32>(3u, 4u)))"},
// OpImageGather 2DDepth Array
ImageAccessCase{"%float 2D 1 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_2d_array;)",
"textureGather(x_20, x_10, coords123.xy, "
"i32(round(coords123.z)))"},
// OpImageGather 2DDepth Array ConstOffset signed
ImageAccessCase{
"%float 2D 1 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1 ConstOffset %offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_2d_array;)",
"textureGather(x_20, x_10, coords123.xy, "
"i32(round(coords123.z)), vec2<i32>(3, 4))"},
// OpImageGather 2DDepth Array ConstOffset unsigned
ImageAccessCase{"%float 2D 1 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1 ConstOffset "
"%u_offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_2d_array;)",
"textureGather(x_20, x_10, coords123.xy, "
"i32(round(coords123.z)), "
"vec2<i32>(vec2<u32>(3u, 4u)))"},
// OpImageGather DepthCube
ImageAccessCase{"%float Cube 1 0 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords123 %int_1",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_cube;)",
"textureGather(x_20, x_10, coords123)"},
// OpImageGather DepthCube Array
ImageAccessCase{"%float Cube 1 1 0 1 Unknown",
"%result = OpImageGather "
"%v4float %sampled_image %coords1234 %int_1",
R"([[group(0), binding(0)]] var x_10 : sampler;
[[group(2), binding(1)]] var x_20 : texture_depth_cube_array;)",
"textureGather(x_20, x_10, coords1234.xyz, "
"i32(round(coords1234.w)))"}}));
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
DISABLED_ImageDrefGather, ImageDrefGather,
SpvParserHandleTest_SampledImageAccessTest, SpvParserHandleTest_SampledImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{ ::testing::ValuesIn(std::vector<ImageAccessCase>{
// TODO(dneto): OpImageDrefGather // TODO(dneto): OpImageDrefGather 2DDepth
// TODO(dneto): OpImageDrefGather with ConstOffset (signed and // TODO(dneto): OpImageDrefGather 2DDepth ConstOffset signed
// unsigned) // TODO(dneto): OpImageDrefGather 2DDepth ConstOffset unsigned
// TODO(dneto): OpImageDrefGather with Offset (signed and unsigned) // TODO(dneto): OpImageDrefGather 2DDepth Array
// TODO(dneto): OpImageDrefGather with Offsets (signed and unsigned) // TODO(dneto): OpImageDrefGather 2DDepth Array ConstOffset signed
// TODO(dneto): OpImageDrefGather 2DDepth Array ConstOffset unsigned
// TODO(dneto): OpImageDrefGather DepthCube
// TODO(dneto): OpImageDrefGather DepthCube Array
})); }));
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -3458,21 +3604,21 @@ INSTANTIATE_TEST_SUITE_P(
{"%uint 2D 0 0 0 1 Unknown", {"%uint 2D 0 0 0 1 Unknown",
"%result = OpImageFetch %v4uint %sampled_image %vf12 ConstOffset " "%result = OpImageFetch %v4uint %sampled_image %vf12 ConstOffset "
"%the_vu12", "%the_vu12",
"ConstOffset is only permitted for sampling operations: ", "ConstOffset is only permitted for sampling, gather, or "
"depth-reference gather operations: ",
{}}, {}},
// ImageRead // ImageRead
{"%uint 2D 0 0 0 2 Rgba32ui", {"%uint 2D 0 0 0 2 Rgba32ui",
"%result = OpImageRead %v4uint %im %vu12 ConstOffset %the_vu12", "%result = OpImageRead %v4uint %im %vu12 ConstOffset %the_vu12",
"ConstOffset is only permitted for sampling operations: ", "ConstOffset is only permitted for sampling, gather, or "
"depth-reference gather operations: ",
{}}, {}},
// ImageWrite // ImageWrite
{"%uint 2D 0 0 0 2 Rgba32ui", {"%uint 2D 0 0 0 2 Rgba32ui",
"OpImageWrite %im %vu12 %vu1234 ConstOffset %the_vu12", "OpImageWrite %im %vu12 %vu1234 ConstOffset %the_vu12",
"ConstOffset is only permitted for sampling operations: ", "ConstOffset is only permitted for sampling, gather, or "
{}} "depth-reference gather operations: ",
// TODO(dneto): Gather {}}}));
// TODO(dneto): DrefGather
}));
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
ConstOffset_BadDim_Errors, ConstOffset_BadDim_Errors,