From e9915cea8d7da75fba6eaca2b02db219252c1e89 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Mon, 9 Sep 2024 13:09:19 -0400 Subject: [PATCH] Update sampled image validation (#5789) Fixes #5781 * Requires all image operands to match except for depth between operand and result --- source/val/validate_image.cpp | 24 +++- test/val/val_image_test.cpp | 229 +++++++++++++++++++++++++++++++++- 2 files changed, 248 insertions(+), 5 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index faf661afb..e77fc1299 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1005,7 +1005,8 @@ bool IsAllowedSampledImageOperand(spv::Op opcode, ValidationState_t& _) { spv_result_t ValidateSampledImage(ValidationState_t& _, const Instruction* inst) { - if (_.GetIdOpcode(inst->type_id()) != spv::Op::OpTypeSampledImage) { + auto type_inst = _.FindDef(inst->type_id()); + if (type_inst->opcode() != spv::Op::OpTypeSampledImage) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Result Type to be OpTypeSampledImage."; } @@ -1022,8 +1023,25 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, << "Corrupt image type definition"; } - // TODO(atgoo@github.com) Check compatibility of result type and received - // image. + // Image operands must match except for depth. + auto sampled_image_id = type_inst->GetOperandAs(1); + if (sampled_image_id != image_type) { + ImageTypeInfo sampled_info; + if (!GetImageTypeInfo(_, sampled_image_id, &sampled_info)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Corrupt image type definition"; + } + if (info.sampled_type != sampled_info.sampled_type || + info.dim != sampled_info.dim || info.arrayed != sampled_info.arrayed || + info.multisampled != sampled_info.multisampled || + info.sampled != sampled_info.sampled || + info.format != sampled_info.format || + info.access_qualifier != sampled_info.access_qualifier) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image operands must match result image operands except for " + "depth"; + } + } if (spvIsVulkanEnv(_.context()->target_env)) { if (info.sampled != 1) { diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 77b042f04..07f0200e2 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -4451,7 +4451,7 @@ TEST_F(ValidateImage, QuerySizeNotImage) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageQuerySize %u32vec2 %sampler )"; @@ -4465,7 +4465,7 @@ TEST_F(ValidateImage, QuerySizeSampledImageDirectly) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageQuerySize %u32vec2 %simg )"; @@ -10647,6 +10647,231 @@ TEST_F(ValidateImage, ImageMSArray_ArrayedTypeDoesNotRequireCapability) { EXPECT_THAT(getDiagnosticString(), Eq("")); } +TEST_F(ValidateImage, SampledImageTypeDepthMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 1 0 0 1 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, SampledImageTypeArrayedMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 1 0 1 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeMultisampledMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 0 1 1 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeSampledMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 0 0 0 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_UNIVERSAL_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeFormatMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 0 0 1 R32f +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_UNIVERSAL_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeAccessQualifierMismatch) { + const std::string code = R"( +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 0 Unknown ReadWrite +%im2_ty = OpTypeImage %float 2D 0 0 0 0 Unknown ReadOnly +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_UNIVERSAL_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + } // namespace } // namespace val } // namespace spvtools