Skip to content

Commit

Permalink
Update sampled image validation
Browse files Browse the repository at this point in the history
Fixes KhronosGroup#5781

* Requires all image operands to match except for depth between operand
  and result
  • Loading branch information
alan-baker committed Sep 9, 2024
1 parent 07f49ce commit aff310a
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 3 deletions.
23 changes: 22 additions & 1 deletion source/val/validate_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.";
}
Expand All @@ -1022,6 +1023,26 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
<< "Corrupt image type definition";
}

// Image operands must match except for depth.
auto sampled_image_id = type_inst->GetOperandAs<uint32_t>(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";
}
}

// TODO([email protected]) Check compatibility of result type and received
// image.

Expand Down
229 changes: 227 additions & 2 deletions test/val/val_image_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
)";

Expand All @@ -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
)";

Expand Down Expand Up @@ -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

0 comments on commit aff310a

Please sign in to comment.