mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
Validator: Validate OpImageTexelPointer (#487)
Checked all instructions whose object is OpTypeSampledImage or OpTypeImage as suggested in #487. OpImageTexelPointer instruction is missing and others look good. This commit adds only OpImageTexelPointer.
This commit is contained in:
parent
a78fa0978d
commit
4b4bd4c53a
@ -793,6 +793,110 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateImageTexelPointer(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
const auto result_type = _.FindDef(inst->type_id());
|
||||
if (result_type->opcode() != SpvOpTypePointer) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Result Type to be OpTypePointer";
|
||||
}
|
||||
|
||||
const auto storage_class = result_type->GetOperandAs<uint32_t>(1);
|
||||
if (storage_class != SpvStorageClassImage) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Result Type to be OpTypePointer whose Storage Class "
|
||||
"operand is Image";
|
||||
}
|
||||
|
||||
const auto ptr_type = result_type->GetOperandAs<uint32_t>(2);
|
||||
const auto ptr_opcode = _.GetIdOpcode(ptr_type);
|
||||
if (ptr_opcode != SpvOpTypeInt && ptr_opcode != SpvOpTypeFloat &&
|
||||
ptr_opcode != SpvOpTypeVoid) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Result Type to be OpTypePointer whose Type operand "
|
||||
"must be a scalar numerical type or OpTypeVoid";
|
||||
}
|
||||
|
||||
const auto image_ptr = _.FindDef(_.GetOperandTypeId(inst, 2));
|
||||
if (!image_ptr || image_ptr->opcode() != SpvOpTypePointer) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Image to be OpTypePointer";
|
||||
}
|
||||
|
||||
const auto image_type = image_ptr->GetOperandAs<uint32_t>(2);
|
||||
if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Image to be OpTypePointer with Type OpTypeImage";
|
||||
}
|
||||
|
||||
ImageTypeInfo info;
|
||||
if (!GetImageTypeInfo(_, image_type, &info)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Corrupt image type definition";
|
||||
}
|
||||
|
||||
if (info.sampled_type != ptr_type) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Image 'Sampled Type' to be the same as the Type "
|
||||
"pointed to by Result Type";
|
||||
}
|
||||
|
||||
if (info.dim == SpvDimSubpassData) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Image Dim SubpassData cannot be used with OpImageTexelPointer";
|
||||
}
|
||||
|
||||
const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
|
||||
if (!coord_type || !_.IsIntScalarOrVectorType(coord_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Coordinate to be integer scalar or vector";
|
||||
}
|
||||
|
||||
uint32_t expected_coord_size = 0;
|
||||
if (info.arrayed == 0) {
|
||||
expected_coord_size = GetPlaneCoordSize(info);
|
||||
} else if (info.arrayed == 1) {
|
||||
switch (info.dim) {
|
||||
case SpvDim1D:
|
||||
expected_coord_size = 2;
|
||||
break;
|
||||
case SpvDimCube:
|
||||
case SpvDim2D:
|
||||
expected_coord_size = 3;
|
||||
break;
|
||||
default:
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Image 'Dim' must be one of 1D, 2D, or Cube when "
|
||||
"Arrayed is 1";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t actual_coord_size = _.GetDimension(coord_type);
|
||||
if (expected_coord_size != actual_coord_size) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Coordinate to have " << expected_coord_size
|
||||
<< " components, but given " << actual_coord_size;
|
||||
}
|
||||
|
||||
const uint32_t sample_type = _.GetOperandTypeId(inst, 4);
|
||||
if (!sample_type || !_.IsIntScalarType(sample_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Sample to be integer scalar";
|
||||
}
|
||||
|
||||
if (info.multisampled == 0) {
|
||||
uint64_t ms = 0;
|
||||
if (!_.GetConstantValUint64(inst->GetOperandAs<uint32_t>(4), &ms) ||
|
||||
ms != 0) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Sample for Image with MS 0 to be a valid <id> for "
|
||||
"the value 0";
|
||||
}
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) {
|
||||
const SpvOp opcode = inst->opcode();
|
||||
uint32_t actual_result_type = 0;
|
||||
@ -1580,6 +1684,8 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) {
|
||||
return ValidateTypeSampledImage(_, inst);
|
||||
case SpvOpSampledImage:
|
||||
return ValidateSampledImage(_, inst);
|
||||
case SpvOpImageTexelPointer:
|
||||
return ValidateImageTexelPointer(_, inst);
|
||||
|
||||
case SpvOpImageSampleImplicitLod:
|
||||
case SpvOpImageSampleExplicitLod:
|
||||
|
@ -46,6 +46,7 @@ OpCapability ImageQuery
|
||||
OpCapability Int64
|
||||
OpCapability Float64
|
||||
OpCapability SparseResidency
|
||||
OpCapability ImageBuffer
|
||||
)";
|
||||
|
||||
if (env == SPV_ENV_UNIVERSAL_1_0) {
|
||||
@ -209,6 +210,22 @@ OpCapability SparseResidency
|
||||
%type_sampler = OpTypeSampler
|
||||
%ptr_sampler = OpTypePointer UniformConstant %type_sampler
|
||||
%uniform_sampler = OpVariable %ptr_sampler UniformConstant
|
||||
|
||||
%type_image_u32_buffer_0002_r32ui = OpTypeImage %u32 Buffer 0 0 0 2 R32ui
|
||||
%ptr_Image_u32 = OpTypePointer Image %u32
|
||||
%ptr_image_u32_buffer_0002_r32ui = OpTypePointer Private %type_image_u32_buffer_0002_r32ui
|
||||
%private_image_u32_buffer_0002_r32ui = OpVariable %ptr_image_u32_buffer_0002_r32ui Private
|
||||
|
||||
%ptr_Image_u32arr4 = OpTypePointer Image %u32arr4
|
||||
|
||||
%type_image_u32_spd_0002 = OpTypeImage %u32 SubpassData 0 0 0 2 Unknown
|
||||
%ptr_image_u32_spd_0002 = OpTypePointer Private %type_image_u32_spd_0002
|
||||
%private_image_u32_spd_0002 = OpVariable %ptr_image_u32_spd_0002 Private
|
||||
|
||||
%type_image_f32_buffer_0002_r32ui = OpTypeImage %f32 Buffer 0 0 0 2 R32ui
|
||||
%ptr_Image_f32 = OpTypePointer Image %f32
|
||||
%ptr_image_f32_buffer_0002_r32ui = OpTypePointer Private %type_image_f32_buffer_0002_r32ui
|
||||
%private_image_f32_buffer_0002_r32ui = OpVariable %ptr_image_f32_buffer_0002_r32ui Private
|
||||
)";
|
||||
|
||||
if (env == SPV_ENV_UNIVERSAL_1_0) {
|
||||
@ -593,6 +610,157 @@ TEST_F(ValidateImage, SampledImageNotSampler) {
|
||||
HasSubstr("Expected Sampler to be of type OpTypeSampler"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerSuccess) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerResultTypeNotPointer) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %type_image_u32_buffer_0002_r32ui %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Expected Result Type to be OpTypePointer"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerResultTypeNotImageClass) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_image_f32_cube_0101 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Expected Result Type to be OpTypePointer whose "
|
||||
"Storage Class operand is Image"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerResultTypeNotNumericNorVoid) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32arr4 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Expected Result Type to be OpTypePointer whose Type operand "
|
||||
"must be a scalar numerical type or OpTypeVoid"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerImageNotResultTypePointer) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %type_image_f32_buffer_0002_r32ui %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Expected Image to be OpTypePointer"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerImageNotImage) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_sampler %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Expected Image to be OpTypePointer with Type OpTypeImage"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerImageSampledNotResultType) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_f32_cube_0101 %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Expected Image 'Sampled Type' to be the same as the "
|
||||
"Type pointed to by Result Type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerImageDimSubpassDataBad) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_spd_0002 %u32_0 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Image Dim SubpassData cannot be used with OpImageTexelPointer"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerImageCoordTypeBad) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_f32 %private_image_f32_buffer_0002_r32ui %f32_0 %f32_0
|
||||
%sum = OpAtomicIAdd %f32 %texel_ptr %f32_1 %f32_0 %f32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Expected Coordinate to be integer scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerImageCoordSizeBad) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_u32_2d_0000 %u32vec3_012 %u32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Expected Coordinate to have 2 components, but given 3"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerSampleNotIntScalar) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %f32_0
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Expected Sample to be integer scalar"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, ImageTexelPointerSampleNotZeroForImageWithMSZero) {
|
||||
const std::string body = R"(
|
||||
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_1
|
||||
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Expected Sample for Image with MS 0 to be a valid "
|
||||
"<id> for the value 0"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateImage, SampleImplicitLodSuccess) {
|
||||
const std::string body = R"(
|
||||
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
|
||||
|
Loading…
Reference in New Issue
Block a user