diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc index f0869019d0..a51cc24dd8 100644 --- a/src/reader/spirv/function.cc +++ b/src/reader/spirv/function.cc @@ -494,8 +494,9 @@ bool IsSampledImageAccess(SpvOp opcode) { } // @param opcode a SPIR-V opcode -// @returns true if the given instruction is an image sampling operation. -bool IsImageSampling(SpvOp opcode) { +// @returns true if the given instruction is an image sampling, gather, +// or gather-compare operation. +bool IsImageSamplingOrGatherOrDrefGather(SpvOp opcode) { switch (opcode) { case SpvOpImageSampleImplicitLod: case SpvOpImageSampleExplicitLod: @@ -506,6 +507,8 @@ bool IsImageSampling(SpvOp opcode) { case SpvOpImageSampleProjExplicitLod: case SpvOpImageSampleProjDrefImplicitLod: case SpvOpImageSampleProjDrefExplicitLod: + case SpvOpImageGather: + case SpvOpImageDrefGather: return true; default: break; @@ -5247,6 +5250,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) { } params.push_back(GetImageExpression(inst)); + // Form the sampler operand, if needed. if (IsSampledImageAccess(opcode)) { // Form the sampler operand. 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); if (!texture_ptr_type) { return Fail(); @@ -5309,8 +5314,16 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) { } break; case SpvOpImageGather: + builtin_name = "textureGather"; + if (!texture_type->Is()) { + // 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: - return Fail() << " image gather is not yet supported"; + return Fail() << " image dref gather is not yet supported"; case SpvOpImageFetch: case SpvOpImageRead: // 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 && (image_operands_mask & SpvImageOperandsConstOffsetMask)) { - if (!IsImageSampling(opcode)) { - return Fail() << "ConstOffset is only permitted for sampling operations: " + if (!IsImageSamplingOrGatherOrDrefGather(opcode)) { + return Fail() << "ConstOffset is only permitted for sampling, gather, or " + "depth-reference gather operations: " << inst.PrettyPrint(); } switch (texture_type->dims) { diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc index 0215bc64df..5d99c184c6 100644 --- a/src/reader/spirv/parser_impl_handle_test.cc +++ b/src/reader/spirv/parser_impl_handle_test.cc @@ -929,6 +929,7 @@ TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, Variable) { EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_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. @@ -986,6 +987,7 @@ TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, FunctionParam) { EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_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. @@ -1004,8 +1006,6 @@ INSTANTIATE_TEST_SUITE_P( SpvParserHandleTest_RegisterHandleUsage_SampledImage, ::testing::Values( - // Test image gather even though WGSL doesn't support it yet. - // OpImageGather UsageImageAccessCase{"%result = OpImageGather " "%v4float %sampled_image %coords %uint_1", @@ -1565,24 +1565,170 @@ TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, DISABLED_FunctionParam) {} INSTANTIATE_TEST_SUITE_P( - DISABLED_ImageGather, + ImageGather, SpvParserHandleTest_SampledImageAccessTest, ::testing::ValuesIn(std::vector{ - // TODO(dneto): OpImageGather - // TODO(dneto): OpImageGather with ConstOffset (signed and unsigned) - // TODO(dneto): OpImageGather with Offset (signed and unsigned) - // TODO(dneto): OpImageGather with Offsets (signed and unsigned) - })); + // OpImageGather 2D + ImageAccessCase{"%float 2D 0 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_2d;)", + "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;)", + "textureGather(1, x_20, x_10, coords12, vec2(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;)", + "textureGather(1, x_20, x_10, coords12, " + "vec2(vec2(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;)", + "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;)", + "textureGather(1, x_20, x_10, coords123.xy, " + "i32(round(coords123.z)), vec2(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;)", + "textureGather(1, x_20, x_10, coords123.xy, " + "i32(round(coords123.z)), " + "vec2(vec2(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;)", + "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;)", + "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(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(vec2(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(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(vec2(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( - DISABLED_ImageDrefGather, + ImageDrefGather, SpvParserHandleTest_SampledImageAccessTest, ::testing::ValuesIn(std::vector{ - // TODO(dneto): OpImageDrefGather - // TODO(dneto): OpImageDrefGather with ConstOffset (signed and - // unsigned) - // TODO(dneto): OpImageDrefGather with Offset (signed and unsigned) - // TODO(dneto): OpImageDrefGather with Offsets (signed and unsigned) + // TODO(dneto): OpImageDrefGather 2DDepth + // TODO(dneto): OpImageDrefGather 2DDepth ConstOffset signed + // TODO(dneto): OpImageDrefGather 2DDepth ConstOffset unsigned + // TODO(dneto): OpImageDrefGather 2DDepth Array + // 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( @@ -3458,21 +3604,21 @@ INSTANTIATE_TEST_SUITE_P( {"%uint 2D 0 0 0 1 Unknown", "%result = OpImageFetch %v4uint %sampled_image %vf12 ConstOffset " "%the_vu12", - "ConstOffset is only permitted for sampling operations: ", + "ConstOffset is only permitted for sampling, gather, or " + "depth-reference gather operations: ", {}}, // ImageRead {"%uint 2D 0 0 0 2 Rgba32ui", "%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 {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vu12 %vu1234 ConstOffset %the_vu12", - "ConstOffset is only permitted for sampling operations: ", - {}} - // TODO(dneto): Gather - // TODO(dneto): DrefGather - })); + "ConstOffset is only permitted for sampling, gather, or " + "depth-reference gather operations: ", + {}}})); INSTANTIATE_TEST_SUITE_P( ConstOffset_BadDim_Errors,