@@ -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.
183273bool 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;
0 commit comments