Skip to content

Commit db13543

Browse files
spirv-val: Add Vulkan Image Format check
1 parent 5d6745b commit db13543

File tree

3 files changed

+468
-25
lines changed

3 files changed

+468
-25
lines changed

source/val/validate_image.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,96 @@ bool IsValidGatherLodBiasAMD(const ValidationState_t& _, spv::Op opcode) {
178178
return false;
179179
}
180180

181+
// Signed or Unsigned Integer Format
182+
bool IsIntImageFormat(spv::ImageFormat format) {
183+
switch (format) {
184+
case spv::ImageFormat::Rgba32i:
185+
case spv::ImageFormat::Rgba16i:
186+
case spv::ImageFormat::Rgba8i:
187+
case spv::ImageFormat::R32i:
188+
case spv::ImageFormat::Rg32i:
189+
case spv::ImageFormat::Rg16i:
190+
case spv::ImageFormat::Rg8i:
191+
case spv::ImageFormat::R16i:
192+
case spv::ImageFormat::R8i:
193+
case spv::ImageFormat::Rgba32ui:
194+
case spv::ImageFormat::Rgba16ui:
195+
case spv::ImageFormat::Rgba8ui:
196+
case spv::ImageFormat::R32ui:
197+
case spv::ImageFormat::Rgb10a2ui:
198+
case spv::ImageFormat::Rg32ui:
199+
case spv::ImageFormat::Rg16ui:
200+
case spv::ImageFormat::Rg8ui:
201+
case spv::ImageFormat::R16ui:
202+
case spv::ImageFormat::R8ui:
203+
case spv::ImageFormat::R64ui:
204+
case spv::ImageFormat::R64i:
205+
return true;
206+
default:
207+
break;
208+
}
209+
return false;
210+
}
211+
212+
bool IsInt64ImageFormat(spv::ImageFormat format) {
213+
switch (format) {
214+
case spv::ImageFormat::R64ui:
215+
case spv::ImageFormat::R64i:
216+
return true;
217+
default:
218+
break;
219+
}
220+
return false;
221+
}
222+
223+
bool IsSignedIntImageFormat(spv::ImageFormat format) {
224+
switch (format) {
225+
case spv::ImageFormat::Rgba32i:
226+
case spv::ImageFormat::Rgba16i:
227+
case spv::ImageFormat::Rgba8i:
228+
case spv::ImageFormat::R32i:
229+
case spv::ImageFormat::Rg32i:
230+
case spv::ImageFormat::Rg16i:
231+
case spv::ImageFormat::Rg8i:
232+
case spv::ImageFormat::R16i:
233+
case spv::ImageFormat::R8i:
234+
case spv::ImageFormat::R64i:
235+
return true;
236+
default:
237+
break;
238+
}
239+
return false;
240+
}
241+
242+
bool IsFloatImageFormat(spv::ImageFormat format) {
243+
switch (format) {
244+
case spv::ImageFormat::Rgba32f:
245+
case spv::ImageFormat::Rgba16f:
246+
case spv::ImageFormat::R32f:
247+
case spv::ImageFormat::Rgba8:
248+
case spv::ImageFormat::Rgba8Snorm:
249+
case spv::ImageFormat::Rg32f:
250+
case spv::ImageFormat::Rg16f:
251+
case spv::ImageFormat::R11fG11fB10f:
252+
case spv::ImageFormat::R16f:
253+
case spv::ImageFormat::Rgba16:
254+
case spv::ImageFormat::Rgb10A2:
255+
case spv::ImageFormat::Rg16:
256+
case spv::ImageFormat::Rg8:
257+
case spv::ImageFormat::R16:
258+
case spv::ImageFormat::R8:
259+
case spv::ImageFormat::Rgba16Snorm:
260+
case spv::ImageFormat::Rg16Snorm:
261+
case spv::ImageFormat::Rg8Snorm:
262+
case spv::ImageFormat::R16Snorm:
263+
case spv::ImageFormat::R8Snorm:
264+
return true;
265+
default:
266+
break;
267+
}
268+
return false;
269+
}
270+
181271
// Returns true if the opcode is a Image instruction which applies
182272
// homogenous projection to the coordinates.
183273
bool IsProj(spv::Op opcode) {
@@ -304,6 +394,33 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
304394
"multi-sampled image";
305395
}
306396

397+
// The following OpTypeImage checks are done here as they depend of if the
398+
// SignExtend and ZeroExtend are used to override the signedness
399+
const bool is_sign_extend =
400+
mask & uint32_t(spv::ImageOperandsMask::SignExtend);
401+
const bool is_zero_extend =
402+
mask & uint32_t(spv::ImageOperandsMask::ZeroExtend);
403+
if (spvIsVulkanEnv(_.context()->target_env)) {
404+
if (info.format != spv::ImageFormat::Unknown &&
405+
_.IsIntScalarType(info.sampled_type)) {
406+
const bool is_format_signed = IsSignedIntImageFormat(info.format);
407+
// (vkspec.html#spirvenv-image-signedness) has order signedness is set by
408+
bool is_sampled_type_signed =
409+
is_sign_extend
410+
? true
411+
: (is_zero_extend
412+
? false
413+
: (_.IsSignedIntScalarType(info.sampled_type) ? true
414+
: false));
415+
if (is_format_signed != is_sampled_type_signed) {
416+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
417+
<< _.VkErrorID(4965)
418+
<< "Image Format signedness does not match Sample Type operand "
419+
"including possible SignExtend or ZeroExtend operand";
420+
}
421+
}
422+
}
423+
307424
// After this point, only set bits in the image operands mask can cause
308425
// the module to be invalid.
309426
if (mask == 0) return SPV_SUCCESS;
@@ -659,6 +776,12 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
659776
// void, and the Format is Unknown.
660777
// In Vulkan, the texel type is only known in all cases by the pipeline
661778
// setup.
779+
if (!_.IsIntScalarOrVectorType(inst->type_id())) {
780+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
781+
<< _.VkErrorID(4965)
782+
<< "Using SignExtend, but result type is not a scalar or vector "
783+
"integer type.";
784+
}
662785
}
663786

664787
if (mask & uint32_t(spv::ImageOperandsMask::ZeroExtend)) {
@@ -672,6 +795,11 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
672795
// void, and the Format is Unknown.
673796
// In Vulkan, the texel type is only known in all cases by the pipeline
674797
// setup.
798+
if (!_.IsUnsignedIntScalarOrVectorType(inst->type_id())) {
799+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
800+
<< _.VkErrorID(4965)
801+
<< "Using ZeroExtend, but result type is a signed integer type.";
802+
}
675803
}
676804

677805
if (mask & uint32_t(spv::ImageOperandsMask::Offsets)) {
@@ -958,6 +1086,33 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
9581086
<< _.VkErrorID(9638)
9591087
<< "Dim must not be Rect in the Vulkan environment";
9601088
}
1089+
1090+
// Can't check signedness here due to image operands able to override
1091+
// sampled type
1092+
if (info.format != spv::ImageFormat::Unknown) {
1093+
// validated above so can assume this is a 32-bit float, 32-bit int, or
1094+
// 64-bit int
1095+
const bool is_int = _.IsIntScalarType(info.sampled_type);
1096+
const bool is_float = !is_int;
1097+
if ((is_float && !IsFloatImageFormat(info.format)) ||
1098+
(is_int && !IsIntImageFormat(info.format))) {
1099+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1100+
<< _.VkErrorID(4965)
1101+
<< "Image Format type does not match Sample Type operand ("
1102+
<< (is_int ? "integer" : "float") << ")";
1103+
} else if (is_int) {
1104+
const uint32_t bit_width = _.GetBitWidth(info.sampled_type);
1105+
// format check above to be int
1106+
if ((bit_width == 32 && IsInt64ImageFormat(info.format)) ||
1107+
(bit_width == 64 && !IsInt64ImageFormat(info.format))) {
1108+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1109+
<< _.VkErrorID(4965)
1110+
<< "Image Format width does not match Sample Type "
1111+
"operand (bit width of "
1112+
<< bit_width << ")";
1113+
}
1114+
}
1115+
}
9611116
}
9621117

9631118
return SPV_SUCCESS;

source/val/validation_state.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,6 +2749,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
27492749
return VUID_WRAP(VUID-StandaloneSpirv-Component-04922);
27502750
case 4923:
27512751
return VUID_WRAP(VUID-StandaloneSpirv-Component-04923);
2752+
case 4965:
2753+
return VUID_WRAP(VUID-StandaloneSpirv-Image-04965);
27522754
case 6201:
27532755
return VUID_WRAP(VUID-StandaloneSpirv-Flat-06201);
27542756
case 6202:

0 commit comments

Comments
 (0)