// 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;
}
}
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);
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";
}
}
}
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 "
}
}
- 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)) {
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.
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);
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";
}
}
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;
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);
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)) {
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);
}
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);
}
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);
}
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);
}
}
}
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);
}
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);
}
}
<< 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) {
<< 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)
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
_.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);
}
}
!_.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;
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;
}
OpCapability SampledRect
OpCapability ImageQuery
OpCapability Int64
+OpCapability SparseResidency
)";
ss << capabilities_and_extensions;
%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
%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
}
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) {
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