spirv-val: Add Mesh Primitive Built-In validaiton (#5529)

This commit is contained in:
Spencer Fricke 2024-02-02 04:20:42 +09:00 committed by GitHub
parent 5d3c8b73f7
commit 61c51d4baf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 449 additions and 3 deletions

View File

@ -118,13 +118,15 @@ typedef enum VUIDError_ {
VUIDErrorMax,
} VUIDError;
const static uint32_t NumVUIDBuiltins = 36;
const static uint32_t NumVUIDBuiltins = 39;
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}},
@ -163,8 +165,11 @@ 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}},
// clang-format on
}};
uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
uint32_t vuid = 0;
@ -356,6 +361,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|
@ -546,6 +554,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|.
//
@ -581,6 +594,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);
@ -909,6 +926,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,
@ -4108,6 +4164,119 @@ 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);
if (builtin == 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;
}
}
if (builtin == 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;
}
}
if (builtin == 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;
}
}
}
// 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,
uint32_t(builtin))
<< " 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,
uint32_t(builtin))
<< " 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]);
@ -4283,6 +4452,11 @@ 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: {
return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst);
}
case spv::BuiltIn::PrimitiveShadingRateKHR: {
return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
}

View File

@ -2259,6 +2259,24 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808);
case 6925:
return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925);
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:

View File

@ -4261,6 +4261,260 @@ INSTANTIATE_TEST_SUITE_P(
Values(TestResult(SPV_ERROR_INVALID_DATA,
"needs to be a 3-component 32-bit float vector"))));
std::string GenerateMeshShadingCode(const std::string& built_in,
const std::string& execution_mode,
const std::string& body,
const std::string& declarations = "") {
std::ostringstream ss;
ss << R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main" %var
OpExecutionMode %main LocalSize 1 1 1
OpExecutionMode %main OutputVertices 1
OpExecutionMode %main OutputPrimitivesEXT 16
)";
ss << "OpExecutionMode %main " << execution_mode << "\n";
ss << "OpDecorate %var BuiltIn " << built_in << "\n";
ss << R"(
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%v2uint = OpTypeVector %uint 2
%v3uint = OpTypeVector %uint 3
%int_0 = OpConstant %int 0
%uint_16 = OpConstant %uint 16
)";
ss << declarations;
ss << R"(
%main = OpFunction %void None %func
%main_entry = OpLabel
)";
ss << body;
ss << R"(
OpReturn
OpFunctionEnd)";
return ss.str();
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTSuccess) {
const std::string declarations = R"(
%array = OpTypeArray %v3uint %uint_16
%array_ptr = OpTypePointer Output %array
%var = OpVariable %array_ptr Output
%ptr = OpTypePointer Output %v3uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
"OutputTrianglesEXT", body, declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTStorageClass) {
const std::string declarations = R"(
%array = OpTypeArray %v3uint %uint_16
%array_ptr = OpTypePointer Input %array
%var = OpVariable %array_ptr Input
%ptr = OpTypePointer Input %v3uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
"OutputTrianglesEXT", body, declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-PrimitiveTriangleIndicesEXT-"
"PrimitiveTriangleIndicesEXT-07055"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTVectorSize) {
const std::string declarations = R"(
%array = OpTypeArray %v2uint %uint_16
%array_ptr = OpTypePointer Output %array
%var = OpVariable %array_ptr Output
%ptr = OpTypePointer Output %v2uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
"OutputTrianglesEXT", body, declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-PrimitiveTriangleIndicesEXT-"
"PrimitiveTriangleIndicesEXT-07056"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTNonArray) {
const std::string declarations = R"(
%ptr = OpTypePointer Output %v3uint
%var = OpVariable %ptr Output
)";
const std::string body = R"(
%load = OpLoad %v3uint %var
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT",
"OutputTrianglesEXT", body, declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-PrimitiveTriangleIndicesEXT-"
"PrimitiveTriangleIndicesEXT-07056"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTSuccess) {
const std::string declarations = R"(
%array = OpTypeArray %v2uint %uint_16
%array_ptr = OpTypePointer Output %array
%var = OpVariable %array_ptr Output
%ptr = OpTypePointer Output %v2uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body,
declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTStorageClass) {
const std::string declarations = R"(
%array = OpTypeArray %v2uint %uint_16
%array_ptr = OpTypePointer Input %array
%var = OpVariable %array_ptr Input
%ptr = OpTypePointer Input %v2uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body,
declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(
getDiagnosticString(),
AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTType) {
const std::string declarations = R"(
%array = OpTypeArray %v3uint %uint_16
%array_ptr = OpTypePointer Input %array
%var = OpVariable %array_ptr Input
%ptr = OpTypePointer Input %v3uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body,
declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(
getDiagnosticString(),
AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTSuccess) {
const std::string declarations = R"(
%array = OpTypeArray %uint %uint_16
%array_ptr = OpTypePointer Output %array
%var = OpVariable %array_ptr Output
%ptr = OpTypePointer Output %uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body,
declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTStorageClass) {
const std::string declarations = R"(
%array = OpTypeArray %uint %uint_16
%array_ptr = OpTypePointer Input %array
%var = OpVariable %array_ptr Input
%ptr = OpTypePointer Input %uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body,
declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(
getDiagnosticString(),
AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTType) {
const std::string declarations = R"(
%array = OpTypeArray %v3uint %uint_16
%array_ptr = OpTypePointer Output %array
%var = OpVariable %array_ptr Output
%ptr = OpTypePointer Output %v3uint
)";
const std::string body = R"(
%access = OpAccessChain %ptr %var %int_0
)";
CompileSuccessfully(
GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body,
declarations)
.c_str(),
SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(
getDiagnosticString(),
AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044"));
}
} // namespace
} // namespace val
} // namespace spvtools