spirv-reader: support OpImageDrefGather

Also, issue an error when a gather or dref-gather operation
is used with a Bias or Grad image operand.

Fixed: tint:1336
Change-Id: Ife11d2f52a1a2d1b75e26269373db5cc4b3440bf
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/74801
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: David Neto <dneto@google.com>
This commit is contained in:
David Neto 2022-01-04 22:00:59 +00:00 committed by Tint LUCI CQ
parent 5791197e80
commit 4beeaea9da
2 changed files with 163 additions and 32 deletions

View File

@ -5286,9 +5286,24 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
const auto num_args = inst.NumInOperands(); const auto num_args = inst.NumInOperands();
// Consumes the depth-reference argument, pushing it onto the end of
// the parameter list. Issues a diagnostic and returns false on error.
auto consume_dref = [&]() -> bool {
if (arg_index < num_args) {
params.push_back(MakeOperand(inst, arg_index).expr);
arg_index++;
} else {
return Fail()
<< "image depth-compare instruction is missing a Dref operand: "
<< inst.PrettyPrint();
}
return true;
};
std::string builtin_name; std::string builtin_name;
bool use_level_of_detail_suffix = true; bool use_level_of_detail_suffix = true;
bool is_dref_sample = false; bool is_dref_sample = false;
bool is_gather_or_dref_gather = false;
bool is_non_dref_sample = false; bool is_non_dref_sample = false;
switch (opcode) { switch (opcode) {
case SpvOpImageSampleImplicitLod: case SpvOpImageSampleImplicitLod:
@ -5304,16 +5319,12 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
case SpvOpImageSampleProjDrefExplicitLod: case SpvOpImageSampleProjDrefExplicitLod:
is_dref_sample = true; is_dref_sample = true;
builtin_name = "textureSampleCompare"; builtin_name = "textureSampleCompare";
if (arg_index < num_args) { if (!consume_dref()) {
params.push_back(MakeOperand(inst, arg_index).expr); return false;
arg_index++;
} else {
return Fail()
<< "image depth-compare instruction is missing a Dref operand: "
<< inst.PrettyPrint();
} }
break; break;
case SpvOpImageGather: case SpvOpImageGather:
is_gather_or_dref_gather = true;
builtin_name = "textureGather"; builtin_name = "textureGather";
if (!texture_type->Is<DepthTexture>()) { if (!texture_type->Is<DepthTexture>()) {
// The explicit component is the *first* argument in WGSL. // The explicit component is the *first* argument in WGSL.
@ -5323,7 +5334,12 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
arg_index++; arg_index++;
break; break;
case SpvOpImageDrefGather: case SpvOpImageDrefGather:
return Fail() << " image dref gather is not yet supported"; is_gather_or_dref_gather = true;
builtin_name = "textureGatherCompare";
if (!consume_dref()) {
return false;
}
break;
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.
@ -5367,6 +5383,11 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
"level-of-detail bias: " "level-of-detail bias: "
<< inst.PrettyPrint(); << inst.PrettyPrint();
} }
if (is_gather_or_dref_gather) {
return Fail() << "WGSL does not support image gather with "
"level-of-detail bias: "
<< inst.PrettyPrint();
}
builtin_name += "Bias"; builtin_name += "Bias";
params.push_back(MakeOperand(inst, arg_index).expr); params.push_back(MakeOperand(inst, arg_index).expr);
image_operands_mask ^= SpvImageOperandsBiasMask; image_operands_mask ^= SpvImageOperandsBiasMask;
@ -5376,9 +5397,11 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
if (use_level_of_detail_suffix) { if (use_level_of_detail_suffix) {
builtin_name += "Level"; builtin_name += "Level";
} }
if (is_dref_sample) { if (is_dref_sample || is_gather_or_dref_gather) {
// Metal only supports Lod = 0 for comparison sampling without // Metal only supports Lod = 0 for comparison sampling without
// derivatives. // derivatives.
// Vulkan SPIR-V does not allow Lod with OpImageGather or
// OpImageDrefGather.
if (!IsFloatZero(inst.GetSingleWordInOperand(arg_index))) { if (!IsFloatZero(inst.GetSingleWordInOperand(arg_index))) {
return Fail() << "WGSL comparison sampling without derivatives " return Fail() << "WGSL comparison sampling without derivatives "
"requires level-of-detail 0.0" "requires level-of-detail 0.0"
@ -5412,6 +5435,11 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
"explicit gradient: " "explicit gradient: "
<< inst.PrettyPrint(); << inst.PrettyPrint();
} }
if (is_gather_or_dref_gather) {
return Fail() << "WGSL does not support image gather with "
"explicit gradient: "
<< inst.PrettyPrint();
}
builtin_name += "Grad"; builtin_name += "Grad";
params.push_back(MakeOperand(inst, arg_index).expr); params.push_back(MakeOperand(inst, arg_index).expr);
params.push_back(MakeOperand(inst, arg_index + 1).expr); params.push_back(MakeOperand(inst, arg_index + 1).expr);
@ -5475,8 +5503,8 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
// compare sample f32 DrefImplicitLod f32 // compare sample f32 DrefImplicitLod f32
// compare sample f32 DrefExplicitLod f32 // compare sample f32 DrefExplicitLod f32
// texel load vec4 ImageFetch f32 // texel load vec4 ImageFetch f32
// normal gather vec4 ImageGather vec4 TODO(dneto) // normal gather vec4 ImageGather vec4
// dref gather vec4 ImageFetch vec4 TODO(dneto) // dref gather vec4 ImageDrefGather vec4
// Construct a 4-element vector with the result from the builtin in the // Construct a 4-element vector with the result from the builtin in the
// first component. // first component.
if (texture_type->IsAnyOf<DepthTexture, DepthMultisampledTexture>()) { if (texture_type->IsAnyOf<DepthTexture, DepthMultisampledTexture>()) {

View File

@ -929,12 +929,6 @@ 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) {
// WGSL does not support Gather instructions yet.
// So don't emit them as part of a "passing" corpus.
p->DeliberatelyInvalidSpirv();
}
if (inst.find("ImageQueryLod") != std::string::npos) { if (inst.find("ImageQueryLod") != std::string::npos) {
// WGSL does not support querying image level of detail. // WGSL does not support querying image level of detail.
// So don't emit them as part of a "passing" corpus. // So don't emit them as part of a "passing" corpus.
@ -987,12 +981,6 @@ 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) {
// WGSL does not support Gather instructions yet.
// So don't emit them as part of a "passing" corpus.
p->DeliberatelyInvalidSpirv();
}
if (inst.find("ImageQueryLod") != std::string::npos) { if (inst.find("ImageQueryLod") != std::string::npos) {
// WGSL does not support querying image level of detail. // WGSL does not support querying image level of detail.
// So don't emit them as part of a "passing" corpus. // So don't emit them as part of a "passing" corpus.
@ -1721,15 +1709,87 @@ INSTANTIATE_TEST_SUITE_P(
ImageDrefGather, ImageDrefGather,
SpvParserHandleTest_SampledImageAccessTest, SpvParserHandleTest_SampledImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{ ::testing::ValuesIn(std::vector<ImageAccessCase>{
// TODO(dneto): OpImageDrefGather 2DDepth // OpImageDrefGather 2DDepth
// TODO(dneto): OpImageDrefGather 2DDepth ConstOffset signed ImageAccessCase{
// TODO(dneto): OpImageDrefGather 2DDepth ConstOffset unsigned "%float 2D 1 0 0 1 Unknown",
// TODO(dneto): OpImageDrefGather 2DDepth Array "%result = OpImageDrefGather "
// TODO(dneto): OpImageDrefGather 2DDepth Array ConstOffset signed "%v4float %sampled_image %coords12 %depth",
// TODO(dneto): OpImageDrefGather 2DDepth Array ConstOffset unsigned R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
// TODO(dneto): OpImageDrefGather DepthCube
// TODO(dneto): OpImageDrefGather DepthCube Array [[group(2), binding(1)]] var x_20 : texture_depth_2d;)",
})); "textureGatherCompare(x_20, x_10, coords12, 0.200000003)"},
// OpImageDrefGather 2DDepth ConstOffset signed
ImageAccessCase{
"%float 2D 1 0 0 1 Unknown",
"%result = OpImageDrefGather "
"%v4float %sampled_image %coords12 %depth ConstOffset %offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
[[group(2), binding(1)]] var x_20 : texture_depth_2d;)",
"textureGatherCompare(x_20, x_10, coords12, 0.200000003, "
"vec2<i32>(3, 4))"},
// OpImageDrefGather 2DDepth ConstOffset unsigned
ImageAccessCase{
"%float 2D 1 0 0 1 Unknown",
"%result = OpImageDrefGather "
"%v4float %sampled_image %coords12 %depth ConstOffset "
"%u_offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
[[group(2), binding(1)]] var x_20 : texture_depth_2d;)",
"textureGatherCompare(x_20, x_10, coords12, 0.200000003, "
"vec2<i32>(vec2<u32>(3u, 4u)))"},
// OpImageDrefGather 2DDepth Array
ImageAccessCase{
"%float 2D 1 1 0 1 Unknown",
"%result = OpImageDrefGather "
"%v4float %sampled_image %coords123 %depth",
R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
[[group(2), binding(1)]] var x_20 : texture_depth_2d_array;)",
"textureGatherCompare(x_20, x_10, coords123.xy, "
"i32(round(coords123.z)), 0.200000003)"},
// OpImageDrefGather 2DDepth Array ConstOffset signed
ImageAccessCase{
"%float 2D 1 1 0 1 Unknown",
"%result = OpImageDrefGather "
"%v4float %sampled_image %coords123 %depth ConstOffset %offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
[[group(2), binding(1)]] var x_20 : texture_depth_2d_array;)",
"textureGatherCompare(x_20, x_10, coords123.xy, "
"i32(round(coords123.z)), 0.200000003, vec2<i32>(3, 4))"},
// OpImageDrefGather 2DDepth Array ConstOffset unsigned
ImageAccessCase{
"%float 2D 1 1 0 1 Unknown",
"%result = OpImageDrefGather "
"%v4float %sampled_image %coords123 %depth ConstOffset "
"%u_offsets2d",
R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
[[group(2), binding(1)]] var x_20 : texture_depth_2d_array;)",
"textureGatherCompare(x_20, x_10, coords123.xy, "
"i32(round(coords123.z)), 0.200000003, "
"vec2<i32>(vec2<u32>(3u, 4u)))"},
// OpImageDrefGather DepthCube
ImageAccessCase{
"%float Cube 1 0 0 1 Unknown",
"%result = OpImageDrefGather "
"%v4float %sampled_image %coords123 %depth",
R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
[[group(2), binding(1)]] var x_20 : texture_depth_cube;)",
"textureGatherCompare(x_20, x_10, coords123, 0.200000003)"},
// OpImageDrefGather DepthCube Array
ImageAccessCase{
"%float Cube 1 1 0 1 Unknown",
"%result = OpImageDrefGather "
"%v4float %sampled_image %coords1234 %depth",
R"([[group(0), binding(0)]] var x_10 : sampler_comparison;
[[group(2), binding(1)]] var x_20 : texture_depth_cube_array;)",
"textureGatherCompare(x_20, x_10, coords1234.xyz, "
"i32(round(coords1234.w)), 0.200000003)"}}));
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
ImageSampleImplicitLod, ImageSampleImplicitLod,
@ -3776,6 +3836,49 @@ INSTANTIATE_TEST_SUITE_P(
"WGSL does not support querying the level of detail of an image: ", "WGSL does not support querying the level of detail of an image: ",
{}}})); {}}}));
INSTANTIATE_TEST_SUITE_P(
ImageGather_Bias_IsError,
SpvParserHandleTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 0 0 0 1 Unknown",
"%result = OpImageGather %v4float %sampled_image %vf12 %int_1 "
"Bias %float_null",
"WGSL does not support image gather with level-of-detail bias: ",
{}}}));
INSTANTIATE_TEST_SUITE_P(
ImageDrefGather_Bias_IsError,
SpvParserHandleTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 1 0 0 1 Unknown",
"%result = OpImageDrefGather %v4float %sampled_image %vf12 %depth "
"Bias %float_null",
"WGSL does not support image gather with level-of-detail bias: ",
{}}}));
// Note: Vulkan SPIR-V ImageGather and ImageDrefGather do not allow explicit
// Lod. The SPIR-V validator should reject those cases already.
INSTANTIATE_TEST_SUITE_P(
ImageGather_Grad_IsError,
SpvParserHandleTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 0 0 0 1 Unknown",
"%result = OpImageGather %v4float %sampled_image %vf12 %int_1 "
"Grad %vf12 %vf12",
"WGSL does not support image gather with explicit gradient: ",
{}}}));
INSTANTIATE_TEST_SUITE_P(
ImageDrefGather_Grad_IsError,
SpvParserHandleTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 1 0 0 1 Unknown",
"%result = OpImageDrefGather %v4float %sampled_image %vf12 %depth "
"Grad %vf12 %vf12",
"WGSL does not support image gather with explicit gradient: ",
{}}}));
TEST_F(SpvParserHandleTest, TEST_F(SpvParserHandleTest,
NeverGenerateConstDeclForHandle_UseVariableDirectly) { NeverGenerateConstDeclForHandle_UseVariableDirectly) {
// An ad-hoc test to prove we never had the issue // An ad-hoc test to prove we never had the issue