Add validator checks for sparse image opcodes

This commit is contained in:
Andrey Tuganov 2017-12-08 17:57:12 -05:00 committed by David Neto
parent 12447d8465
commit c520d43649
2 changed files with 832 additions and 113 deletions

View File

@ -196,7 +196,8 @@ uint32_t GetPlaneCoordSize(const ImageTypeInfo& info) {
// the instruction uses projection coordinates.
uint32_t GetMinCoordSize(SpvOp opcode, const ImageTypeInfo& info) {
if (info.dim == SpvDimCube &&
(opcode == SpvOpImageRead || opcode == SpvOpImageWrite)) {
(opcode == SpvOpImageRead || opcode == SpvOpImageWrite ||
opcode == SpvOpImageSparseRead)) {
// These opcodes use UV for Cube, not direction vector.
return 3;
}
@ -270,7 +271,8 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
}
if (mask & SpvImageOperandsLodMask) {
if (!is_explicit_lod && opcode != SpvOpImageFetch) {
if (!is_explicit_lod && opcode != SpvOpImageFetch &&
opcode != SpvOpImageSparseFetch) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Image Operand Lod can only be used with ExplicitLod opcodes "
<< "and OpImageFetch: " << spvOpcodeString(opcode);
@ -287,14 +289,14 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
if (is_explicit_lod) {
if (!_.IsFloatScalarType(type_id)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Image Operand Lod to be float scalar when used with "
<< "ExplicitLod: " << spvOpcodeString(opcode);
<< "Expected Image Operand Lod to be float scalar when used "
<< "with ExplicitLod: " << spvOpcodeString(opcode);
}
} else {
if (!_.IsIntScalarType(type_id)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Image Operand Lod to be int scalar when used with "
<< "OpImageFetch";
<< "Expected Image Operand Lod to be int scalar when used with "
<< "OpImageFetch";
}
}
@ -411,7 +413,9 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
}
if (mask & SpvImageOperandsConstOffsetsMask) {
if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather) {
if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather &&
opcode != SpvOpImageSparseGather &&
opcode != SpvOpImageSparseDrefGather) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Image Operand ConstOffsets can only be used with "
"OpImageGather "
@ -544,7 +548,8 @@ spv_result_t ValidateImageCommon(ValidationState_t& _,
}
}
if (opcode == SpvOpImageRead || opcode == SpvOpImageWrite) {
if (opcode == SpvOpImageRead || opcode == SpvOpImageSparseRead ||
opcode == SpvOpImageWrite) {
if (info.sampled == 0) {
} else if (info.sampled == 2) {
if (info.dim == SpvDim1D && !_.HasCapability(SpvCapabilityImage1D)) {
@ -589,6 +594,73 @@ spv_result_t ValidateImageCommon(ValidationState_t& _,
return SPV_SUCCESS;
}
// Returns true if opcode is *ImageSparse*, false otherwise.
bool IsSparse(SpvOp opcode) {
switch (opcode) {
case SpvOpImageSparseSampleImplicitLod:
case SpvOpImageSparseSampleExplicitLod:
case SpvOpImageSparseSampleDrefImplicitLod:
case SpvOpImageSparseSampleDrefExplicitLod:
case SpvOpImageSparseSampleProjImplicitLod:
case SpvOpImageSparseSampleProjExplicitLod:
case SpvOpImageSparseSampleProjDrefImplicitLod:
case SpvOpImageSparseSampleProjDrefExplicitLod:
case SpvOpImageSparseFetch:
case SpvOpImageSparseGather:
case SpvOpImageSparseDrefGather:
case SpvOpImageSparseTexelsResident:
case SpvOpImageSparseRead: {
return true;
}
default: { return false; }
}
return false;
}
// Checks sparse image opcode result type and returns the second struct member.
// Returns inst.type_id for non-sparse image opcodes.
// Not valid for sparse image opcodes which do not return a struct.
spv_result_t GetActualResultType(ValidationState_t& _,
const spv_parsed_instruction_t& inst,
uint32_t* actual_result_type) {
const SpvOp opcode = static_cast<SpvOp>(inst.opcode);
if (IsSparse(opcode)) {
const Instruction* const type_inst = _.FindDef(inst.type_id);
assert(type_inst);
if (!type_inst || type_inst->opcode() != SpvOpTypeStruct) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": expected Result Type to be OpTypeStruct";
}
if (type_inst->words().size() != 4 ||
!_.IsIntScalarType(type_inst->word(2))) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": expected Result Type to be a struct containing an int "
"scalar "
<< "and a texel";
}
*actual_result_type = type_inst->word(3);
} else {
*actual_result_type = inst.type_id;
}
return SPV_SUCCESS;
}
// Returns a string describing actual result type of an opcode.
// Not valid for sparse image opcodes which do not return a struct.
const char* GetActualResultTypeStr(SpvOp opcode) {
if (IsSparse(opcode)) return "Result Type's second member";
return "Result Type";
}
} // namespace
// Validates correctness of image instructions.
@ -610,7 +682,7 @@ spv_result_t ImagePass(ValidationState_t& _,
ImageTypeInfo info;
if (!GetImageTypeInfo(_, inst->words[1], &info)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "OpTypeImage: corrupt definition";
<< "OpTypeImage: corrupt definition";
}
const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type);
@ -618,48 +690,48 @@ spv_result_t ImagePass(ValidationState_t& _,
sampled_type_opcode != SpvOpTypeInt &&
sampled_type_opcode != SpvOpTypeFloat) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": expected Sampled Type to be either void or numerical scalar "
<< "type";
<< spvOpcodeString(opcode)
<< ": expected Sampled Type to be either void or numerical "
<< "scalar type";
}
// Dim is checked elsewhere.
if (info.depth > 2) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": invalid Depth " << info.depth << " (must be 0, 1 or 2)";
<< spvOpcodeString(opcode) << ": invalid Depth " << info.depth
<< " (must be 0, 1 or 2)";
}
if (info.arrayed > 1) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": invalid Arrayed " << info.arrayed << " (must be 0 or 1)";
<< spvOpcodeString(opcode) << ": invalid Arrayed "
<< info.arrayed << " (must be 0 or 1)";
}
if (info.multisampled > 1) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": invalid MS " << info.multisampled << " (must be 0 or 1)";
<< spvOpcodeString(opcode) << ": invalid MS "
<< info.multisampled << " (must be 0 or 1)";
}
if (info.sampled > 2) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": invalid Sampled " << info.sampled << " (must be 0, 1 or 2)";
<< spvOpcodeString(opcode) << ": invalid Sampled "
<< info.sampled << " (must be 0, 1 or 2)";
}
if (info.dim == SpvDimSubpassData) {
if (info.sampled != 2) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": Dim SubpassData requires Sampled to be 2";
<< spvOpcodeString(opcode)
<< ": Dim SubpassData requires Sampled to be 2";
}
if (info.format != SpvImageFormatUnknown) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": Dim SubpassData requires format Unknown";
<< spvOpcodeString(opcode)
<< ": Dim SubpassData requires format Unknown";
}
}
@ -672,8 +744,8 @@ spv_result_t ImagePass(ValidationState_t& _,
const uint32_t image_type = inst->words[2];
if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": expected Image to be of type OpTypeImage";
<< spvOpcodeString(opcode)
<< ": expected Image to be of type OpTypeImage";
}
break;
@ -726,18 +798,27 @@ spv_result_t ImagePass(ValidationState_t& _,
case SpvOpImageSampleImplicitLod:
case SpvOpImageSampleExplicitLod:
case SpvOpImageSampleProjImplicitLod:
case SpvOpImageSampleProjExplicitLod: {
if (!_.IsIntVectorType(result_type) &&
!_.IsFloatVectorType(result_type)) {
case SpvOpImageSampleProjExplicitLod:
case SpvOpImageSparseSampleImplicitLod:
case SpvOpImageSparseSampleExplicitLod: {
uint32_t actual_result_type = 0;
if (spv_result_t error =
GetActualResultType(_, *inst, &actual_result_type)) {
return error;
}
if (!_.IsIntVectorType(actual_result_type) &&
!_.IsFloatVectorType(actual_result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to be int or float vector type: "
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to be int or float vector type: "
<< spvOpcodeString(opcode);
}
if (_.GetDimension(result_type) != 4) {
if (_.GetDimension(actual_result_type) != 4) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to have 4 components: "
<< spvOpcodeString(opcode);
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to have 4 components: " << spvOpcodeString(opcode);
}
const uint32_t image_type = _.GetOperandTypeId(inst, 2);
@ -757,17 +838,19 @@ spv_result_t ImagePass(ValidationState_t& _,
return result;
if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
const uint32_t result_component_type = _.GetComponentType(result_type);
if (result_component_type != info.sampled_type) {
const uint32_t texel_component_type =
_.GetComponentType(actual_result_type);
if (texel_component_type != info.sampled_type) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Image 'Sampled Type' to be the same as Result "
"Type "
<< "components: " << spvOpcodeString(opcode);
<< "Expected Image 'Sampled Type' to be the same as "
<< GetActualResultTypeStr(opcode)
<< " components: " << spvOpcodeString(opcode);
}
}
const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
if (opcode == SpvOpImageSampleExplicitLod &&
if ((opcode == SpvOpImageSampleExplicitLod ||
opcode == SpvOpImageSparseSampleExplicitLod) &&
_.HasCapability(SpvCapabilityKernel)) {
if (!_.IsFloatScalarOrVectorType(coord_type) &&
!_.IsIntScalarOrVectorType(coord_type)) {
@ -808,11 +891,20 @@ spv_result_t ImagePass(ValidationState_t& _,
case SpvOpImageSampleDrefImplicitLod:
case SpvOpImageSampleDrefExplicitLod:
case SpvOpImageSampleProjDrefImplicitLod:
case SpvOpImageSampleProjDrefExplicitLod: {
if (!_.IsIntScalarType(result_type) &&
!_.IsFloatScalarType(result_type)) {
case SpvOpImageSampleProjDrefExplicitLod:
case SpvOpImageSparseSampleDrefImplicitLod:
case SpvOpImageSparseSampleDrefExplicitLod: {
uint32_t actual_result_type = 0;
if (spv_result_t error =
GetActualResultType(_, *inst, &actual_result_type)) {
return error;
}
if (!_.IsIntScalarType(actual_result_type) &&
!_.IsFloatScalarType(actual_result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to be int or float scalar type: "
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to be int or float scalar type: "
<< spvOpcodeString(opcode);
}
@ -832,10 +924,10 @@ spv_result_t ImagePass(ValidationState_t& _,
if (spv_result_t result = ValidateImageCommon(_, *inst, info))
return result;
if (result_type != info.sampled_type) {
if (actual_result_type != info.sampled_type) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Image 'Sampled Type' to be the same as Result "
"Type: "
<< "Expected Image 'Sampled Type' to be the same as "
<< GetActualResultTypeStr(opcode) << ": "
<< spvOpcodeString(opcode);
}
@ -875,18 +967,26 @@ spv_result_t ImagePass(ValidationState_t& _,
break;
}
case SpvOpImageFetch: {
if (!_.IsIntVectorType(result_type) &&
!_.IsFloatVectorType(result_type)) {
case SpvOpImageFetch:
case SpvOpImageSparseFetch: {
uint32_t actual_result_type = 0;
if (spv_result_t error =
GetActualResultType(_, *inst, &actual_result_type)) {
return error;
}
if (!_.IsIntVectorType(actual_result_type) &&
!_.IsFloatVectorType(actual_result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to be int or float vector type: "
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to be int or float vector type: "
<< spvOpcodeString(opcode);
}
if (_.GetDimension(result_type) != 4) {
if (_.GetDimension(actual_result_type) != 4) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to have 4 components: "
<< spvOpcodeString(opcode);
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to have 4 components: " << spvOpcodeString(opcode);
}
const uint32_t image_type = _.GetOperandTypeId(inst, 2);
@ -903,12 +1003,13 @@ spv_result_t ImagePass(ValidationState_t& _,
}
if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
const uint32_t result_component_type = _.GetComponentType(result_type);
const uint32_t result_component_type =
_.GetComponentType(actual_result_type);
if (result_component_type != info.sampled_type) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Image 'Sampled Type' to be the same as Result "
"Type "
<< "components: " << spvOpcodeString(opcode);
<< "Expected Image 'Sampled Type' to be the same as "
<< GetActualResultTypeStr(opcode)
<< " components: " << spvOpcodeString(opcode);
}
}
@ -950,18 +1051,27 @@ spv_result_t ImagePass(ValidationState_t& _,
}
case SpvOpImageGather:
case SpvOpImageDrefGather: {
if (!_.IsIntVectorType(result_type) &&
!_.IsFloatVectorType(result_type)) {
case SpvOpImageDrefGather:
case SpvOpImageSparseGather:
case SpvOpImageSparseDrefGather: {
uint32_t actual_result_type = 0;
if (spv_result_t error =
GetActualResultType(_, *inst, &actual_result_type)) {
return error;
}
if (!_.IsIntVectorType(actual_result_type) &&
!_.IsFloatVectorType(actual_result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to be int or float vector type: "
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to be int or float vector type: "
<< spvOpcodeString(opcode);
}
if (_.GetDimension(result_type) != 4) {
if (_.GetDimension(actual_result_type) != 4) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to have 4 components: "
<< spvOpcodeString(opcode);
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to have 4 components: " << spvOpcodeString(opcode);
}
const uint32_t image_type = _.GetOperandTypeId(inst, 2);
@ -978,13 +1088,15 @@ spv_result_t ImagePass(ValidationState_t& _,
}
if (opcode == SpvOpImageDrefGather ||
opcode == SpvOpImageSparseDrefGather ||
_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
const uint32_t result_component_type = _.GetComponentType(result_type);
const uint32_t result_component_type =
_.GetComponentType(actual_result_type);
if (result_component_type != info.sampled_type) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Image 'Sampled Type' to be the same as Result "
"Type "
<< "components: " << spvOpcodeString(opcode);
<< "Expected Image 'Sampled Type' to be the same as "
<< GetActualResultTypeStr(opcode)
<< " components: " << spvOpcodeString(opcode);
}
}
@ -1011,7 +1123,7 @@ spv_result_t ImagePass(ValidationState_t& _,
<< spvOpcodeString(opcode);
}
if (opcode == SpvOpImageGather) {
if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) {
const uint32_t component_index_type = _.GetOperandTypeId(inst, 4);
if (!_.IsIntScalarType(component_index_type) ||
_.GetBitWidth(component_index_type) != 32) {
@ -1020,7 +1132,8 @@ spv_result_t ImagePass(ValidationState_t& _,
<< spvOpcodeString(opcode);
}
} else {
assert(opcode == SpvOpImageDrefGather);
assert(opcode == SpvOpImageDrefGather ||
opcode == SpvOpImageSparseDrefGather);
const uint32_t dref_type = _.GetOperandTypeId(inst, 4);
if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) {
return _.diag(SPV_ERROR_INVALID_DATA)
@ -1039,21 +1152,28 @@ spv_result_t ImagePass(ValidationState_t& _,
break;
}
case SpvOpImageRead: {
if (!_.IsIntScalarOrVectorType(result_type) &&
!_.IsFloatScalarOrVectorType(result_type)) {
case SpvOpImageRead:
case SpvOpImageSparseRead: {
uint32_t actual_result_type = 0;
if (spv_result_t error =
GetActualResultType(_, *inst, &actual_result_type)) {
return error;
}
if (!_.IsIntScalarOrVectorType(actual_result_type) &&
!_.IsFloatScalarOrVectorType(actual_result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to be int or float scalar or vector "
"type: "
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to be int or float scalar or vector type: "
<< spvOpcodeString(opcode);
}
#if 0
// TODO(atgoo@github.com) Disabled until the spec is clarified.
if (_.GetDimension(result_type) != 4) {
if (_.GetDimension(actual_result_type) != 4) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Result Type to have 4 components: "
<< spvOpcodeString(opcode);
<< "Expected " << GetActualResultTypeStr(opcode)
<< " to have 4 components: " << spvOpcodeString(opcode);
}
#endif
@ -1074,16 +1194,17 @@ spv_result_t ImagePass(ValidationState_t& _,
_.current_function().RegisterExecutionModelLimitation(
SpvExecutionModelFragment,
std::string("Dim SubpassData requires Fragment execution model: ") +
spvOpcodeString(opcode));
spvOpcodeString(opcode));
}
if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
const uint32_t result_component_type = _.GetComponentType(result_type);
const uint32_t result_component_type =
_.GetComponentType(actual_result_type);
if (result_component_type != info.sampled_type) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Expected Image 'Sampled Type' to be the same as Result "
"Type "
<< "components: " << spvOpcodeString(opcode);
<< "Expected Image 'Sampled Type' to be the same as "
<< GetActualResultTypeStr(opcode)
<< " components: " << spvOpcodeString(opcode);
}
}
@ -1111,8 +1232,7 @@ spv_result_t ImagePass(ValidationState_t& _,
!_.HasCapability(SpvCapabilityStorageImageReadWithoutFormat)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< "Capability StorageImageReadWithoutFormat is required to "
"read "
<< "storage image: " << spvOpcodeString(opcode);
<< "read storage image: " << spvOpcodeString(opcode);
}
if (inst->num_words <= 5) break;
@ -1494,6 +1614,32 @@ spv_result_t ImagePass(ValidationState_t& _,
break;
}
case SpvOpImageSparseSampleProjImplicitLod:
case SpvOpImageSparseSampleProjExplicitLod:
case SpvOpImageSparseSampleProjDrefImplicitLod:
case SpvOpImageSparseSampleProjDrefExplicitLod: {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": instruction reserved for future use, "
<< "use of this instruction is invalid";
}
case SpvOpImageSparseTexelsResident: {
if (!_.IsBoolScalarType(result_type)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": expected Result Type to be bool scalar type";
}
const uint32_t resident_code_type = _.GetOperandTypeId(inst, 2);
if (!_.IsIntScalarType(resident_code_type)) {
return _.diag(SPV_ERROR_INVALID_DATA)
<< spvOpcodeString(opcode)
<< ": expected Resident Code to be int scalar";
}
break;
}
default:
break;
}

View File

@ -43,6 +43,7 @@ OpCapability Sampled1D
OpCapability SampledRect
OpCapability ImageQuery
OpCapability Int64
OpCapability SparseResidency
)";
ss << capabilities_and_extensions;
@ -97,6 +98,18 @@ OpCapability Int64
%u32arr4 = OpTypeArray %u32 %u32_4
%u32vec3arr4 = OpTypeArray %u32vec3 %u32_4
%struct_u32_f32vec4 = OpTypeStruct %u32 %f32vec4
%struct_u64_f32vec4 = OpTypeStruct %u64 %f32vec4
%struct_u32_u32vec4 = OpTypeStruct %u32 %u32vec4
%struct_u32_f32vec3 = OpTypeStruct %u32 %f32vec3
%struct_f32_f32vec4 = OpTypeStruct %f32 %f32vec4
%struct_u32_u32 = OpTypeStruct %u32 %u32
%struct_f32_f32 = OpTypeStruct %f32 %f32
%struct_u32 = OpTypeStruct %u32
%struct_u32_f32_u32 = OpTypeStruct %u32 %f32 %u32
%struct_u32_f32vec4_u32 = OpTypeStruct %u32 %f32vec4 %u32
%struct_u32_u32arr4 = OpTypeStruct %u32 %u32arr4
%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2
%u32vec3_012 = OpConstantComposite %u32vec3 %u32_0 %u32_1 %u32_2
@ -174,7 +187,7 @@ OpCapability Int64
%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Unknown
%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002
%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0001 UniformConstant
%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant
%type_sampled_image_f32_2d_0002 = OpTypeSampledImage %type_image_f32_2d_0002
%type_image_f32_spd_0002 = OpTypeImage %f32 SubpassData 0 0 0 2 Unknown
@ -338,94 +351,96 @@ OpEntryPoint Fragment %main "main"
}
TEST_F(ValidateImage, TypeImageWrongSampledType) {
const std::string code = GetShaderHeader() + R"(
const std::string code = GetShaderHeader() + R"(
%img_type = OpTypeImage %bool 2D 0 0 0 1 Unknown
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeImage: expected Sampled Type to be either void or numerical scalar "
"type"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("TypeImage: expected Sampled Type to be either void or "
"numerical scalar "
"type"));
}
TEST_F(ValidateImage, TypeImageWrongDepth) {
const std::string code = GetShaderHeader() + R"(
const std::string code = GetShaderHeader() + R"(
%img_type = OpTypeImage %f32 2D 3 0 0 1 Unknown
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeImage: invalid Depth 3 (must be 0, 1 or 2)"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("TypeImage: invalid Depth 3 (must be 0, 1 or 2)"));
}
TEST_F(ValidateImage, TypeImageWrongArrayed) {
const std::string code = GetShaderHeader() + R"(
const std::string code = GetShaderHeader() + R"(
%img_type = OpTypeImage %f32 2D 0 2 0 1 Unknown
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeImage: invalid Arrayed 2 (must be 0 or 1)"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("TypeImage: invalid Arrayed 2 (must be 0 or 1)"));
}
TEST_F(ValidateImage, TypeImageWrongMS) {
const std::string code = GetShaderHeader() + R"(
const std::string code = GetShaderHeader() + R"(
%img_type = OpTypeImage %f32 2D 0 0 2 1 Unknown
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeImage: invalid MS 2 (must be 0 or 1)"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("TypeImage: invalid MS 2 (must be 0 or 1)"));
}
TEST_F(ValidateImage, TypeImageWrongSampled) {
const std::string code = GetShaderHeader() + R"(
const std::string code = GetShaderHeader() + R"(
%img_type = OpTypeImage %f32 2D 0 0 0 3 Unknown
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeImage: invalid Sampled 3 (must be 0, 1 or 2)"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("TypeImage: invalid Sampled 3 (must be 0, 1 or 2)"));
}
TEST_F(ValidateImage, TypeImageWrongSampledForSubpassData) {
const std::string code = GetShaderHeader("OpCapability InputAttachment\n") +
R"(
R"(
%img_type = OpTypeImage %f32 SubpassData 0 0 0 1 Unknown
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeImage: Dim SubpassData requires Sampled to be 2"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("TypeImage: Dim SubpassData requires Sampled to be 2"));
}
TEST_F(ValidateImage, TypeImageWrongFormatForSubpassData) {
const std::string code = GetShaderHeader("OpCapability InputAttachment\n") +
R"(
R"(
%img_type = OpTypeImage %f32 SubpassData 0 0 0 2 Rgba32f
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeImage: Dim SubpassData requires format Unknown"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("TypeImage: Dim SubpassData requires format Unknown"));
}
TEST_F(ValidateImage, TypeSampledImageNotImage) {
const std::string code = GetShaderHeader() + R"(
const std::string code = GetShaderHeader() + R"(
%simg_type = OpTypeSampledImage %f32
)";
CompileSuccessfully(code.c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"TypeSampledImage: expected Image to be of type OpTypeImage"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("TypeSampledImage: expected Image to be of type OpTypeImage"));
}
TEST_F(ValidateImage, SampledImageSuccess) {
@ -3369,8 +3384,566 @@ TEST_F(ValidateImage, ReadSubpassDataWrongExecutionModel) {
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra, "Vertex").c_str());
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(), HasSubstr(
"Dim SubpassData requires Fragment execution model: ImageRead"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Dim SubpassData requires Fragment execution model: ImageRead"));
}
TEST_F(ValidateImage, SparseSampleImplicitLodSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh
%res2 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh Bias %f32_0_25
%res4 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh ConstOffset %s32vec2_01
%res5 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh Offset %s32vec2_01
%res6 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh MinLod %f32_0_5
%res7 = OpImageSparseSampleImplicitLod %struct_u64_f32vec4 %simg %f32vec2_hh Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateImage, SparseSampleImplicitLodResultTypeNotStruct) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %f32 %simg %f32vec2_hh
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseSampleImplicitLod: "
"expected Result Type to be OpTypeStruct"));
}
TEST_F(ValidateImage, SparseSampleImplicitLodResultTypeNotTwoMembers1) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %struct_u32 %simg %f32vec2_hh
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseSampleImplicitLod: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseSampleImplicitLodResultTypeNotTwoMembers2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4_u32 %simg %f32vec2_hh
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseSampleImplicitLod: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseSampleImplicitLodResultTypeFirstMemberNotInt) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %struct_f32_f32vec4 %simg %f32vec2_hh
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseSampleImplicitLod: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseSampleImplicitLodResultTypeTexelNotVector) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %struct_u32_u32 %simg %f32vec2_hh
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type's second member to be int or "
"float vector type: ImageSparseSampleImplicitLod"));
}
TEST_F(ValidateImage, SparseSampleImplicitLodWrongNumComponentsTexel) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %struct_u32_f32vec3 %simg %f32vec2_hh
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type's second member to have 4 "
"components: ImageSparseSampleImplicitLod"));
}
TEST_F(ValidateImage, SparseSampleImplicitLodWrongComponentTypeTexel) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleImplicitLod %struct_u32_u32vec4 %simg %f32vec2_hh
)";
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 "
"Result Type's second member components: "
"ImageSparseSampleImplicitLod"));
}
TEST_F(ValidateImage, SparseSampleDrefImplicitLodSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0001 %uniform_image_u32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_u32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1
%res2 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 Bias %f32_0_25
%res4 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 ConstOffset %s32vec2_01
%res5 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 Offset %s32vec2_01
%res6 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 MinLod %f32_0_5
%res7 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateImage, SparseSampleDrefImplicitLodResultTypeNotStruct) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleDrefImplicitLod %f32 %simg %f32vec2_hh %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseSampleDrefImplicitLod: "
"expected Result Type to be OpTypeStruct"));
}
TEST_F(ValidateImage, SparseSampleDrefImplicitLodResultTypeNotTwoMembers1) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleDrefImplicitLod %struct_u32 %simg %f32vec2_hh %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("ImageSparseSampleDrefImplicitLod: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseSampleDrefImplicitLodResultTypeNotTwoMembers2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleDrefImplicitLod %struct_u32_f32_u32 %simg %f32vec2_hh %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("ImageSparseSampleDrefImplicitLod: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseSampleDrefImplicitLodResultTypeFirstMemberNotInt) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleDrefImplicitLod %struct_f32_f32 %simg %f32vec2_hh %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("ImageSparseSampleDrefImplicitLod: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseSampleDrefImplicitLodDifferentSampledType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_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 "
"Result Type's second member: "
"ImageSparseSampleDrefImplicitLod"));
}
TEST_F(ValidateImage, SparseFetchSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %struct_u32_f32vec4 %img %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateImage, SparseFetchResultTypeNotStruct) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %f32 %img %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseFetch: "
"expected Result Type to be OpTypeStruct"));
}
TEST_F(ValidateImage, SparseFetchResultTypeNotTwoMembers1) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %struct_u32 %img %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseFetch: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseFetchResultTypeNotTwoMembers2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %struct_u32_f32vec4_u32 %img %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseFetch: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseFetchResultTypeFirstMemberNotInt) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %struct_f32_f32vec4 %img %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseFetch: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseFetchResultTypeTexelNotVector) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %struct_u32_u32 %img %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type's second member to be int or "
"float vector type: ImageSparseFetch"));
}
TEST_F(ValidateImage, SparseFetchWrongNumComponentsTexel) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %struct_u32_f32vec3 %img %u32vec2_01
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type's second member to have 4 "
"components: ImageSparseFetch"));
}
TEST_F(ValidateImage, SparseFetchWrongComponentTypeTexel) {
const std::string body = R"(
%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001
%res1 = OpImageSparseFetch %struct_u32_u32vec4 %img %u32vec2_01
)";
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 "
"Result Type's second member components: "
"ImageSparseFetch"));
}
TEST_F(ValidateImage, SparseReadSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
%res1 = OpImageSparseRead %struct_u32_f32vec4 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateImage, SparseReadResultTypeNotStruct) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
%res1 = OpImageSparseRead %f32 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseRead: "
"expected Result Type to be OpTypeStruct"));
}
TEST_F(ValidateImage, SparseReadResultTypeNotTwoMembers1) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
%res1 = OpImageSparseRead %struct_u32 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseRead: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseReadResultTypeNotTwoMembers2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
%res1 = OpImageSparseRead %struct_u32_f32vec4_u32 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseRead: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseReadResultTypeFirstMemberNotInt) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
%res1 = OpImageSparseRead %struct_f32_f32vec4 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseRead: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseReadResultTypeTexelWrongType) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
%res1 = OpImageSparseRead %struct_u32_u32arr4 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type's second member to be int or "
"float scalar or vector type: ImageSparseRead"));
}
TEST_F(ValidateImage, SparseReadWrongComponentTypeTexel) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002
%res1 = OpImageSparseRead %struct_u32_u32vec4 %img %u32vec2_01
)";
const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n";
CompileSuccessfully(GenerateShaderCode(body, extra).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Image 'Sampled Type' to be the same as "
"Result Type's second member components: "
"ImageSparseRead"));
}
TEST_F(ValidateImage, SparseGatherSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %struct_u32_f32vec4 %simg %f32vec4_0000 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateImage, SparseGatherResultTypeNotStruct) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %f32 %simg %f32vec2_hh %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseGather: "
"expected Result Type to be OpTypeStruct"));
}
TEST_F(ValidateImage, SparseGatherResultTypeNotTwoMembers1) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %struct_u32 %simg %f32vec2_hh %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseGather: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseGatherResultTypeNotTwoMembers2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %struct_u32_f32vec4_u32 %simg %f32vec2_hh %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseGather: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseGatherResultTypeFirstMemberNotInt) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %struct_f32_f32vec4 %simg %f32vec2_hh %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseGather: expected Result Type "
"to be a struct containing an int scalar and a texel"));
}
TEST_F(ValidateImage, SparseGatherResultTypeTexelNotVector) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %struct_u32_u32 %simg %f32vec2_hh %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type's second member to be int or "
"float vector type: ImageSparseGather"));
}
TEST_F(ValidateImage, SparseGatherWrongNumComponentsTexel) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %struct_u32_f32vec3 %simg %f32vec2_hh %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type's second member to have 4 "
"components: ImageSparseGather"));
}
TEST_F(ValidateImage, SparseGatherWrongComponentTypeTexel) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
%sampler = OpLoad %type_sampler %uniform_sampler
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
%res1 = OpImageSparseGather %struct_u32_u32vec4 %simg %f32vec2_hh %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 "
"Result Type's second member components: "
"ImageSparseGather"));
}
TEST_F(ValidateImage, SparseTexelsResidentSuccess) {
const std::string body = R"(
%res1 = OpImageSparseTexelsResident %bool %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateImage, SparseTexelsResidentResultTypeNotBool) {
const std::string body = R"(
%res1 = OpImageSparseTexelsResident %u32 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("ImageSparseTexelsResident: "
"expected Result Type to be bool scalar type"));
}
} // anonymous namespace