From b9a2f5946e0c8aae60b73a1474e230fa033ed1e2 Mon Sep 17 00:00:00 2001 From: Austin Eng Date: Fri, 24 Sep 2021 18:00:04 +0000 Subject: [PATCH] spirv-reader: Implement OpImageSampleProj* instructions Bug: tint:1143 Change-Id: Ic07245a2c5afdb2400f3a9777b6fd42f70dab3c8 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/64700 Kokoro: Kokoro Reviewed-by: David Neto Reviewed-by: Ben Clayton Commit-Queue: David Neto --- src/reader/spirv/function.cc | 47 +- src/reader/spirv/parser_impl_handle_test.cc | 911 ++++++++++++++++++++ 2 files changed, 951 insertions(+), 7 deletions(-) diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc index 77c0d848e8..39a06efc25 100644 --- a/src/reader/spirv/function.cc +++ b/src/reader/spirv/function.cc @@ -478,12 +478,16 @@ bool IsSampledImageAccess(SpvOp opcode) { case SpvOpImageSampleExplicitLod: case SpvOpImageSampleDrefImplicitLod: case SpvOpImageSampleDrefExplicitLod: + // WGSL doesn't have *Proj* texturing; spirv reader emulates it. + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: case SpvOpImageGather: case SpvOpImageDrefGather: case SpvOpImageQueryLod: return true; default: - // WGSL doesn't have *Proj* texturing. break; } return false; @@ -497,9 +501,13 @@ bool IsImageSampling(SpvOp opcode) { case SpvOpImageSampleExplicitLod: case SpvOpImageSampleDrefImplicitLod: case SpvOpImageSampleDrefExplicitLod: + // WGSL doesn't have *Proj* texturing; spirv reader emulates it. + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: return true; default: - // WGSL doesn't have *Proj* texturing. break; } return false; @@ -5256,11 +5264,15 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) { switch (opcode) { case SpvOpImageSampleImplicitLod: case SpvOpImageSampleExplicitLod: + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: is_non_dref_sample = true; builtin_name = "textureSample"; break; case SpvOpImageSampleDrefImplicitLod: case SpvOpImageSampleDrefExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: is_dref_sample = true; builtin_name = "textureSampleCompare"; if (arg_index < num_args) { @@ -5304,7 +5316,8 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) { } break; default: - return Fail() << "internal error: sampled image access"; + return Fail() << "internal error: unrecognized image access: " + << inst.PrettyPrint(); } // Loop over the image operands, looking for extra operands to the builtin. @@ -5601,7 +5614,20 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess( << texture_type->TypeInfo().name << " prompted by " << inst.PrettyPrint(); } - const auto num_coords_required = num_axes + (is_arrayed ? 1 : 0); + bool is_proj = false; + switch (inst.opcode()) { + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: + is_proj = true; + break; + default: + break; + } + + const auto num_coords_required = + num_axes + (is_arrayed ? 1 : 0) + (is_proj ? 1 : 0); uint32_t num_coords_supplied = 0; auto* component_type = raw_coords.type; if (component_type->IsFloatScalar() || component_type->IsIntegerScalar()) { @@ -5629,13 +5655,20 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess( // it to a signed value of the same shape (scalar or vector). // Use a lambda to make it easy to only generate the expressions when we // will actually use them. - auto prefix_swizzle_expr = [this, num_axes, component_type, + auto prefix_swizzle_expr = [this, num_axes, component_type, is_proj, raw_coords]() -> ast::Expression* { auto* swizzle_type = (num_axes == 1) ? component_type : ty_.Vector(component_type, num_axes); auto* swizzle = create( Source{}, raw_coords.expr, PrefixSwizzle(num_axes)); - return ToSignedIfUnsigned({swizzle_type, swizzle}).expr; + if (is_proj) { + auto* q = create(Source{}, raw_coords.expr, + Swizzle(num_axes)); + auto* proj_div = builder_.Div(swizzle, q); + return ToSignedIfUnsigned({swizzle_type, proj_div}).expr; + } else { + return ToSignedIfUnsigned({swizzle_type, swizzle}).expr; + } }; if (is_arrayed) { @@ -5650,7 +5683,7 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess( // Convert it to a signed integer type, if needed result.push_back(ToI32({component_type, array_index}).expr); } else { - if (num_coords_supplied == num_coords_required) { + if (num_coords_supplied == num_coords_required && !is_proj) { // Pass the value through, with possible unsigned->signed conversion. result.push_back(ToSignedIfUnsigned(raw_coords).expr); } else { diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc index 99c7d53f12..4c84b8e243 100644 --- a/src/reader/spirv/parser_impl_handle_test.cc +++ b/src/reader/spirv/parser_impl_handle_test.cc @@ -3170,6 +3170,864 @@ INSTANTIATE_TEST_SUITE_P( ScalarConstructor[not set]{0.000000} })"}})); +///// +// Projection sampling +///// + +// Test matrix for projection sampling: +// sampling +// Dimensions: 1D, 2D, 3D, 2DShadow +// Variations: Proj { ImplicitLod { | Bias } | ExplicitLod { Lod | Grad | } } +// x { | ConstOffset } +// depth-compare sampling +// Dimensions: 2D +// Variations: Proj Dref { ImplicitLod { | Bias } | ExplicitLod { Lod | Grad | +// } } x { | ConstOffset } +// +// Expanded: +// ImageSampleProjImplicitLod // { | ConstOffset } +// ImageSampleProjImplicitLod_Bias // { | ConstOffset } +// ImageSampleProjExplicitLod_Lod // { | ConstOffset } +// ImageSampleProjExplicitLod_Grad // { | ConstOffset } +// +// ImageSampleProjImplicitLod_DepthTexture +// +// ImageSampleProjDrefImplicitLod // { | ConstOffset } +// ImageSampleProjDrefExplicitLod_Lod // { | ConstOffset } + +INSTANTIATE_TEST_SUITE_P( + ImageSampleProjImplicitLod, + SpvParserHandleTest_SampledImageAccessTest, + ::testing::Values( + + // OpImageSampleProjImplicitLod 1D + ImageAccessCase{"%float 1D 0 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords12", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_1d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSample} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords12} + Identifier[not set]{x} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords12} + Identifier[not set]{y} + } + } + ) + })"}, + + // OpImageSampleProjImplicitLod 2D + ImageAccessCase{"%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords123", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSample} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + ) + })"}, + + // OpImageSampleProjImplicitLod 3D + ImageAccessCase{"%float 3D 0 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords1234", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_3d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSample} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords1234} + Identifier[not set]{xyz} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords1234} + Identifier[not set]{w} + } + } + ) + })"}, + + // OpImageSampleProjImplicitLod 2D with ConstOffset + // (Don't need to test with 1D or 3D, as the hard part was the splatted + // division.) This case tests handling of the ConstOffset + ImageAccessCase{ + "%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords123 ConstOffset %offsets2d", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSample} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + TypeConstructor[not set]{ + __vec_2__i32 + ScalarConstructor[not set]{3} + ScalarConstructor[not set]{4} + } + ) + })"})); + +INSTANTIATE_TEST_SUITE_P( + ImageSampleProjImplicitLod_Bias, + SpvParserHandleTest_SampledImageAccessTest, + ::testing::Values( + + // OpImageSampleProjImplicitLod with Bias + // Only testing 2D + ImageAccessCase{"%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords123 Bias %float_7", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleBias} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + ScalarConstructor[not set]{7.000000} + ) + })"}, + + // OpImageSampleProjImplicitLod with Bias and signed ConstOffset + ImageAccessCase{"%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords123 Bias|ConstOffset " + "%float_7 %offsets2d", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleBias} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + ScalarConstructor[not set]{7.000000} + TypeConstructor[not set]{ + __vec_2__i32 + ScalarConstructor[not set]{3} + ScalarConstructor[not set]{4} + } + ) + })"}, + + // OpImageSampleProjImplicitLod with Bias and unsigned ConstOffset + // Convert ConstOffset to signed + ImageAccessCase{"%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords123 Bias|ConstOffset " + "%float_7 %u_offsets2d", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleBias} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + ScalarConstructor[not set]{7.000000} + TypeConstructor[not set]{ + __vec_2__i32 + TypeConstructor[not set]{ + __vec_2__u32 + ScalarConstructor[not set]{3u} + ScalarConstructor[not set]{4u} + } + } + ) + })"})); + +INSTANTIATE_TEST_SUITE_P( + ImageSampleProjExplicitLod_Lod, + SpvParserHandleTest_SampledImageAccessTest, + ::testing::Values( + // OpImageSampleProjExplicitLod 2D + ImageAccessCase{"%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjExplicitLod " + "%v4float %sampled_image %coords123 Lod %f1", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleLevel} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + Identifier[not set]{f1} + ) + })"}, + + // OpImageSampleProjExplicitLod 2D Lod with ConstOffset + ImageAccessCase{ + "%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjExplicitLod " + "%v4float %sampled_image %coords123 Lod|ConstOffset %f1 %offsets2d", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleLevel} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + Identifier[not set]{f1} + TypeConstructor[not set]{ + __vec_2__i32 + ScalarConstructor[not set]{3} + ScalarConstructor[not set]{4} + } + ) + })"})); + +INSTANTIATE_TEST_SUITE_P( + ImageSampleProjExplicitLod_Grad, + SpvParserHandleTest_SampledImageAccessTest, + ::testing::Values( + // OpImageSampleProjExplicitLod 2D Grad + ImageAccessCase{"%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjExplicitLod " + "%v4float %sampled_image %coords123 Grad %vf12 %vf21", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleGrad} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + Identifier[not set]{vf12} + Identifier[not set]{vf21} + ) + })"}, + + // OpImageSampleProjExplicitLod 2D Lod Grad ConstOffset + ImageAccessCase{"%float 2D 0 0 0 1 Unknown", + "%result = OpImageSampleProjExplicitLod " + "%v4float %sampled_image %coords123 Grad|ConstOffset " + "%vf12 %vf21 %offsets2d", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __sampled_texture_2d__f32 + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleGrad} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + Identifier[not set]{vf12} + Identifier[not set]{vf21} + TypeConstructor[not set]{ + __vec_2__i32 + ScalarConstructor[not set]{3} + ScalarConstructor[not set]{4} + } + ) + })"})); + +INSTANTIATE_TEST_SUITE_P( + // Ordinary (non-comparison) sampling on a depth texture. + ImageSampleProjImplicitLod_DepthTexture, + SpvParserHandleTest_SampledImageAccessTest, + ::testing::Values( + // OpImageSampleProjImplicitLod 2D depth + ImageAccessCase{"%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjImplicitLod " + "%v4float %sampled_image %coords123", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_sampler + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __depth_texture_2d + })", + // Sampling the depth texture yields an f32, but the + // SPIR-V operation yiedls vec4, so fill out the + // remaining components with 0. + R"( + TypeConstructor[not set]{ + __vec_4__f32 + Call[not set]{ + Identifier[not set]{textureSample} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + ) + } + ScalarConstructor[not set]{0.000000} + ScalarConstructor[not set]{0.000000} + ScalarConstructor[not set]{0.000000} + })"})); + +INSTANTIATE_TEST_SUITE_P( + ImageSampleProjDrefImplicitLod, + SpvParserHandleTest_SampledImageAccessTest, + ::testing::Values( + + // OpImageSampleProjDrefImplicitLod 2D depth-texture + ImageAccessCase{"%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjDrefImplicitLod " + "%float %sampled_image %coords123 %f1", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_comparison + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __depth_texture_2d + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleCompare} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + Identifier[not set]{f1} + ) + })"}, + + // OpImageSampleProjDrefImplicitLod 2D depth-texture, ConstOffset + ImageAccessCase{ + "%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjDrefImplicitLod " + "%float %sampled_image %coords123 %f1 ConstOffset %offsets2d", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_comparison + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __depth_texture_2d + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleCompare} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + Identifier[not set]{f1} + TypeConstructor[not set]{ + __vec_2__i32 + ScalarConstructor[not set]{3} + ScalarConstructor[not set]{4} + } + ) + })"})); + +INSTANTIATE_TEST_SUITE_P( + DISABLED_ImageSampleProjDrefExplicitLod_Lod, + SpvParserHandleTest_SampledImageAccessTest, + ::testing::Values( + + // Lod must be float constant 0 due to a Metal constraint. + // Another test checks cases where the Lod is not float constant 0. + + // OpImageSampleProjDrefExplicitLod 2D depth-texture Lod + ImageAccessCase{"%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjDrefExplicitLod " + "%float %sampled_image %coords123 %depth Lod %float_0", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_comparison + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __depth_texture_2d + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleCompare} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + ScalarConstructor[not set]{0.200000} + ScalarConstructor[not set]{0.000000} + ) + })"}, + + // OpImageSampleProjDrefImplicitLod 2D depth-texture, Lod ConstOffset + ImageAccessCase{"%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjDrefExplicitLod " + "%float %sampled_image %coords123 %depth " + "Lod|ConstOffset %float_0 %offsets2d", + R"( + Variable{ + Decorations{ + GroupDecoration{0} + BindingDecoration{0} + } + x_10 + none + undefined + __sampler_comparison + } + Variable{ + Decorations{ + GroupDecoration{2} + BindingDecoration{1} + } + x_20 + none + undefined + __depth_texture_2d + })", + R"( + Call[not set]{ + Identifier[not set]{textureSampleCompareLevel} + ( + Identifier[not set]{x_20} + Identifier[not set]{x_10} + Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{coords123} + Identifier[not set]{z} + } + } + ScalarConstructor[not set]{0.200000} + ScalarConstructor[not set]{0.000000} + TypeConstructor[not set]{ + __vec_2__i32 + ScalarConstructor[not set]{3} + ScalarConstructor[not set]{4} + } + ) + })"})); + +///// +// End projection sampling +///// + using SpvParserHandleTest_ImageAccessTest = SpvParserTestBase<::testing::TestWithParam>; @@ -6368,6 +7226,59 @@ INSTANTIATE_TEST_SUITE_P( "0.0", {}}})); +INSTANTIATE_TEST_SUITE_P( + ImageSampleProjDrefExplicitLod_CheckForLod0, + // This is like the previous test, but for Projection sampling. + // + // Metal requires comparison sampling with explicit Level-of-detail to use + // Lod 0. The SPIR-V reader requires the operand to be parsed as a constant + // 0 value. SPIR-V validation requires the Lod parameter to be a floating + // point value for non-fetch operations. So only test float values. + SpvParserHandleTest_ImageCoordsTest, + ::testing::ValuesIn(std::vector{ + // float 0.0 works + {"%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjDrefExplicitLod %float %sampled_image " + "%vf1234 %depth Lod %float_0", + "", + {R"(Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{vf1234} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{vf1234} + Identifier[not set]{z} + } +} +)"}}, + // float null works + {"%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjDrefExplicitLod %float %sampled_image " + "%vf1234 %depth Lod %float_0", + "", + {R"(Binary[not set]{ + MemberAccessor[not set]{ + Identifier[not set]{vf1234} + Identifier[not set]{xy} + } + divide + MemberAccessor[not set]{ + Identifier[not set]{vf1234} + Identifier[not set]{z} + } +} +)"}}, + // float 1.0 fails. + {"%float 2D 1 0 0 1 Unknown", + "%result = OpImageSampleProjDrefExplicitLod %float %sampled_image " + "%vf1234 %depth Lod %float_1", + "WGSL comparison sampling without derivatives requires " + "level-of-detail " + "0.0", + {}}})); + TEST_F(SpvParserHandleTest, CombinedImageSampler_IsError) { const auto assembly = Preamble() + R"( OpEntryPoint Fragment %100 "main"