Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spirv-val: Initial SPV_EXT_mesh_shader builtins #5080

Merged
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
236 changes: 233 additions & 3 deletions source/val/validate_builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,15 @@ typedef enum VUIDError_ {
VUIDErrorMax,
} VUIDError;

const static uint32_t NumVUIDBuiltins = 36;
const static uint32_t NumVUIDBuiltins = 40;

typedef struct {
spv::BuiltIn builtIn;
uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
} BuiltinVUIDMapping;

// Many built-ins have the same checks (Storage Class, Type, etc)
// This table provides a nice LUT for the VUIDs
std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
// clang-format off
{spv::BuiltIn::SubgroupEqMask, {0, 4370, 4371}},
Expand Down Expand Up @@ -165,8 +167,12 @@ std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
{spv::BuiltIn::CullMaskKHR, {6735, 6736, 6737}},
{spv::BuiltIn::BaryCoordKHR, {4154, 4155, 4156}},
{spv::BuiltIn::BaryCoordNoPerspKHR, {4160, 4161, 4162}},
// clang-format off
} };
{spv::BuiltIn::PrimitivePointIndicesEXT, {7041, 7043, 7044}},
{spv::BuiltIn::PrimitiveLineIndicesEXT, {7047, 7049, 7050}},
{spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}},
{spv::BuiltIn::CullPrimitiveEXT, {7034, 7035, 7036}},
// clang-format on
}};

uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
uint32_t vuid = 0;
Expand Down Expand Up @@ -358,6 +364,9 @@ class BuiltInsValidator {
spv_result_t ValidateRayTracingBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst);

spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst);

// The following section contains functions which are called when id defined
// by |referenced_inst| is
// 1. referenced by |referenced_from_inst|
Expand Down Expand Up @@ -548,6 +557,11 @@ class BuiltInsValidator {
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);

spv_result_t ValidateMeshShadingEXTBuiltinsAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);

// Validates that |built_in_inst| is not (even indirectly) referenced from
// within a function which can be called with |execution_model|.
//
Expand All @@ -570,6 +584,9 @@ class BuiltInsValidator {
spv_result_t ValidateBool(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateBoolArr(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateI(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
Expand All @@ -583,6 +600,10 @@ class BuiltInsValidator {
spv_result_t ValidateI32Arr(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateArrayedI32Vec(
const Decoration& decoration, const Instruction& inst,
uint32_t num_components,
const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateOptionalArrayedI32(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
Expand Down Expand Up @@ -765,6 +786,29 @@ spv_result_t BuiltInsValidator::ValidateBool(
return SPV_SUCCESS;
}

spv_result_t BuiltInsValidator::ValidateBoolArr(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag) {
uint32_t underlying_type = 0;
if (spv_result_t error =
GetUnderlyingType(_, decoration, inst, &underlying_type)) {
return error;
}

const Instruction* const type_inst = _.FindDef(underlying_type);
if (type_inst->opcode() != spv::Op::OpTypeArray) {
return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
}

const uint32_t component_type = type_inst->word(2);
if (!_.IsBoolScalarType(component_type)) {
return diag(GetDefinitionDesc(decoration, inst) +
" components are not boolean scalar.");
}

return SPV_SUCCESS;
}

spv_result_t BuiltInsValidator::ValidateI(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag) {
Expand Down Expand Up @@ -911,6 +955,45 @@ spv_result_t BuiltInsValidator::ValidateI32Vec(
return SPV_SUCCESS;
}

spv_result_t BuiltInsValidator::ValidateArrayedI32Vec(
const Decoration& decoration, const Instruction& inst,
uint32_t num_components,
const std::function<spv_result_t(const std::string& message)>& diag) {
uint32_t underlying_type = 0;
if (spv_result_t error =
GetUnderlyingType(_, decoration, inst, &underlying_type)) {
return error;
}

const Instruction* const type_inst = _.FindDef(underlying_type);
if (type_inst->opcode() != spv::Op::OpTypeArray) {
return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
}

const uint32_t component_type = type_inst->word(2);
if (!_.IsIntVectorType(component_type)) {
return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
}

const uint32_t actual_num_components = _.GetDimension(component_type);
if (_.GetDimension(component_type) != num_components) {
std::ostringstream ss;
ss << GetDefinitionDesc(decoration, inst) << " has "
<< actual_num_components << " components.";
return diag(ss.str());
}

const uint32_t bit_width = _.GetBitWidth(component_type);
if (bit_width != 32) {
std::ostringstream ss;
ss << GetDefinitionDesc(decoration, inst)
<< " has components with bit width " << bit_width << ".";
return diag(ss.str());
}

return SPV_SUCCESS;
}

spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
const Decoration& decoration, const Instruction& inst,
uint32_t num_components,
Expand Down Expand Up @@ -4110,6 +4193,147 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
return SPV_SUCCESS;
}

spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
switch (builtin) {
case spv::BuiltIn::PrimitivePointIndicesEXT: {
if (spv_result_t error = ValidateI32Arr(
decoration, inst,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid) << "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 32-bit int array."
<< message;
})) {
return error;
}
break;
}
case spv::BuiltIn::PrimitiveLineIndicesEXT: {
if (spv_result_t error = ValidateArrayedI32Vec(
decoration, inst, 2,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid) << "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 2-component 32-bit int "
"array."
<< message;
})) {
return error;
}
break;
}
case spv::BuiltIn::PrimitiveTriangleIndicesEXT: {
if (spv_result_t error = ValidateArrayedI32Vec(
decoration, inst, 3,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid) << "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 3-component 32-bit int "
"array."
<< message;
})) {
return error;
}
break;
}
case spv::BuiltIn::CullPrimitiveEXT: {
if (spv_result_t error = ValidateBoolArr(
decoration, inst,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid) << "According to the "
<< spvLogStringForEnv(_.context()->target_env)
<< " spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a boolean array." << message;
})) {
return error;
}
break;
}
default:
break;
}
}
// Seed at reference checks with this built-in.
return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst,
inst);
}

spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
const spv::StorageClass storage_class =
GetStorageClass(referenced_from_inst);
if (storage_class != spv::StorageClass::Max &&
storage_class != spv::StorageClass::Output) {
uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Output storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
<< " " << GetStorageClassDesc(referenced_from_inst);
}

for (const spv::ExecutionModel execution_model : execution_models_) {
if (execution_model != spv::ExecutionModel::MeshEXT) {
uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(vuid)
<< spvLogStringForEnv(_.context()->target_env)
<< " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be used only with MeshEXT execution model. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
}
}
}

if (function_id_ == 0) {
// Propagate this rule to all dependant ids in the global scope.
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference,
this, decoration, built_in_inst, referenced_from_inst,
std::placeholders::_1));
}

return SPV_SUCCESS;
}

spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
const Decoration& decoration, const Instruction& inst) {
const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
Expand Down Expand Up @@ -4285,6 +4509,12 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case spv::BuiltIn::CullMaskKHR: {
return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
}
case spv::BuiltIn::PrimitivePointIndicesEXT:
case spv::BuiltIn::PrimitiveLineIndicesEXT:
case spv::BuiltIn::PrimitiveTriangleIndicesEXT:
case spv::BuiltIn::CullPrimitiveEXT: {
return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst);
}
case spv::BuiltIn::PrimitiveShadingRateKHR: {
return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
}
Expand Down
24 changes: 24 additions & 0 deletions source/val/validation_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2165,6 +2165,30 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925);
case 6997:
return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-06997);
case 7034:
return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07034);
case 7035:
return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07035);
case 7036:
return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036);
case 7041:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041);
case 7043:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043);
case 7044:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044);
case 7047:
return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047);
case 7049:
return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049);
case 7050:
return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050);
case 7053:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053);
case 7055:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055);
case 7056:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056);
case 7102:
return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102);
case 7320:
Expand Down
Loading