Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 186 additions & 19 deletions source/val/validate_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,118 @@ bool IsValidGatherLodBiasAMD(const ValidationState_t& _, spv::Op opcode) {
return false;
}

// Signed or Unsigned Integer Format
bool IsIntImageFormat(spv::ImageFormat format) {
switch (format) {
case spv::ImageFormat::Rgba32i:
case spv::ImageFormat::Rgba16i:
case spv::ImageFormat::Rgba8i:
case spv::ImageFormat::R32i:
case spv::ImageFormat::Rg32i:
case spv::ImageFormat::Rg16i:
case spv::ImageFormat::Rg8i:
case spv::ImageFormat::R16i:
case spv::ImageFormat::R8i:
case spv::ImageFormat::Rgba32ui:
case spv::ImageFormat::Rgba16ui:
case spv::ImageFormat::Rgba8ui:
case spv::ImageFormat::R32ui:
case spv::ImageFormat::Rgb10a2ui:
case spv::ImageFormat::Rg32ui:
case spv::ImageFormat::Rg16ui:
case spv::ImageFormat::Rg8ui:
case spv::ImageFormat::R16ui:
case spv::ImageFormat::R8ui:
case spv::ImageFormat::R64ui:
case spv::ImageFormat::R64i:
return true;
default:
break;
}
return false;
}

bool IsInt64ImageFormat(spv::ImageFormat format) {
switch (format) {
case spv::ImageFormat::R64ui:
case spv::ImageFormat::R64i:
return true;
default:
break;
}
return false;
}

bool IsSignedIntImageFormat(spv::ImageFormat format) {
switch (format) {
case spv::ImageFormat::Rgba32i:
case spv::ImageFormat::Rgba16i:
case spv::ImageFormat::Rgba8i:
case spv::ImageFormat::R32i:
case spv::ImageFormat::Rg32i:
case spv::ImageFormat::Rg16i:
case spv::ImageFormat::Rg8i:
case spv::ImageFormat::R16i:
case spv::ImageFormat::R8i:
case spv::ImageFormat::R64i:
return true;
default:
break;
}
return false;
}

bool IsFloatImageFormat(spv::ImageFormat format) {
switch (format) {
case spv::ImageFormat::Rgba32f:
case spv::ImageFormat::Rgba16f:
case spv::ImageFormat::R32f:
case spv::ImageFormat::Rgba8:
case spv::ImageFormat::Rgba8Snorm:
case spv::ImageFormat::Rg32f:
case spv::ImageFormat::Rg16f:
case spv::ImageFormat::R11fG11fB10f:
case spv::ImageFormat::R16f:
case spv::ImageFormat::Rgba16:
case spv::ImageFormat::Rgb10A2:
case spv::ImageFormat::Rg16:
case spv::ImageFormat::Rg8:
case spv::ImageFormat::R16:
case spv::ImageFormat::R8:
case spv::ImageFormat::Rgba16Snorm:
case spv::ImageFormat::Rg16Snorm:
case spv::ImageFormat::Rg8Snorm:
case spv::ImageFormat::R16Snorm:
case spv::ImageFormat::R8Snorm:
return true;
default:
break;
}
return false;
}

bool IsImageSparse(spv::Op opcode) {
switch (opcode) {
case spv::Op::OpImageSparseSampleImplicitLod:
case spv::Op::OpImageSparseSampleExplicitLod:
case spv::Op::OpImageSparseSampleDrefImplicitLod:
case spv::Op::OpImageSparseSampleDrefExplicitLod:
case spv::Op::OpImageSparseSampleProjImplicitLod:
case spv::Op::OpImageSparseSampleProjExplicitLod:
case spv::Op::OpImageSparseSampleProjDrefImplicitLod:
case spv::Op::OpImageSparseSampleProjDrefExplicitLod:
case spv::Op::OpImageSparseFetch:
case spv::Op::OpImageSparseGather:
case spv::Op::OpImageSparseDrefGather:
case spv::Op::OpImageSparseTexelsResident:
case spv::Op::OpImageSparseRead:
return true;
default:
break;
}
return false;
}

// Returns true if the opcode is a Image instruction which applies
// homogenous projection to the coordinates.
bool IsProj(spv::Op opcode) {
Expand Down Expand Up @@ -304,6 +416,33 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
"multi-sampled image";
}

// The following OpTypeImage checks are done here as they depend of if the
// SignExtend and ZeroExtend are used to override the signedness
const bool is_sign_extend =
mask & uint32_t(spv::ImageOperandsMask::SignExtend);
const bool is_zero_extend =
mask & uint32_t(spv::ImageOperandsMask::ZeroExtend);
if (spvIsVulkanEnv(_.context()->target_env)) {
if (info.format != spv::ImageFormat::Unknown &&
_.IsIntScalarType(info.sampled_type)) {
const bool is_format_signed = IsSignedIntImageFormat(info.format);
// (vkspec.html#spirvenv-image-signedness) has order signedness is set by
bool is_sampled_type_signed =
is_sign_extend
? true
: (is_zero_extend
? false
: (_.IsSignedIntScalarType(info.sampled_type) ? true
: false));
if (is_format_signed != is_sampled_type_signed) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(4965)
<< "Image Format signedness does not match Sample Type operand "
"including possible SignExtend or ZeroExtend operand";
}
}
}

// After this point, only set bits in the image operands mask can cause
// the module to be invalid.
if (mask == 0) return SPV_SUCCESS;
Expand Down Expand Up @@ -648,30 +787,31 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
if (auto error = ValidateMemoryScope(_, inst, visible_scope)) return error;
}

if (mask & uint32_t(spv::ImageOperandsMask::SignExtend)) {
// Checked elsewhere: SPIR-V 1.4 version or later.

// "The texel value is converted to the target value via sign extension.
// Only valid when the texel type is a scalar or vector of integer type."
//
// We don't have enough information to know what the texel type is.
// Checked elsewhere: SPIR-V 1.4 version or later.
if (is_sign_extend || is_zero_extend) {
// We don't have enough information to know what the |texel value type| is.
// In OpenCL, knowledge is deferred until runtime: the image SampledType is
// void, and the Format is Unknown.
// In Vulkan, the texel type is only known in all cases by the pipeline
// setup.
}

if (mask & uint32_t(spv::ImageOperandsMask::ZeroExtend)) {
// Checked elsewhere: SPIR-V 1.4 version or later.

// "The texel value is converted to the target value via zero extension.
// Only valid when the texel type is a scalar or vector of integer type."
//
// We don't have enough information to know what the texel type is.
// In OpenCL, knowledge is deferred until runtime: the image SampledType is
// void, and the Format is Unknown.
// In Vulkan, the texel type is only known in all cases by the pipeline
// setup.
if (opcode == spv::Op::OpImageWrite) {
// OpImageWrite has no result type.
// TODO - Add Validation
} else if (IsImageSparse(opcode)) {
// Sparse image read/sample return a struct.
// TODO - Add Validation
} else {
if (is_sign_extend && !_.IsIntScalarOrVectorType(inst->type_id())) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Using SignExtend, but result type is not a scalar or vector "
"integer type.";
} else if (is_zero_extend &&
!_.IsUnsignedIntScalarOrVectorType(inst->type_id())) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Using ZeroExtend, but result type is a signed integer type.";
}
}
}

if (mask & uint32_t(spv::ImageOperandsMask::Offsets)) {
Expand Down Expand Up @@ -958,6 +1098,33 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
<< _.VkErrorID(9638)
<< "Dim must not be Rect in the Vulkan environment";
}

// Can't check signedness here due to image operands (SignExtend or
// ZeroExtend) ability to overridesampled type
if (info.format != spv::ImageFormat::Unknown) {
// validated above so can assume this is a
// 32-bit float, 32-bit int, or 64-bit int
const bool is_int = _.IsIntScalarType(info.sampled_type);
const bool is_float = !is_int;
if ((is_float && !IsFloatImageFormat(info.format)) ||
(is_int && !IsIntImageFormat(info.format))) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(4965)
<< "Image Format type does not match Sample Type operand ("
<< (is_int ? "integer" : "float") << ")";
} else if (is_int) {
const uint32_t bit_width = _.GetBitWidth(info.sampled_type);
// format check above to be int
if ((bit_width == 32 && IsInt64ImageFormat(info.format)) ||
(bit_width == 64 && !IsInt64ImageFormat(info.format))) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(4965)
<< "Image Format width does not match Sample Type "
"operand (bit width of "
<< bit_width << ")";
}
}
}
}

return SPV_SUCCESS;
Expand Down
2 changes: 2 additions & 0 deletions source/val/validation_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2755,6 +2755,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-Component-04922);
case 4923:
return VUID_WRAP(VUID-StandaloneSpirv-Component-04923);
case 4965:
return VUID_WRAP(VUID-StandaloneSpirv-Image-04965);
case 6201:
return VUID_WRAP(VUID-StandaloneSpirv-Flat-06201);
case 6202:
Expand Down
Loading