Add EXT_mesh_shader validation support

1. Each OpEntryPoint with the MeshEXT Execution Model can have at most one global OpVariable of storage class TaskPayloadWorkgroupEXT.
2. PerPrimitiveEXT only be used on a memory object declaration or a member of a structure type
3. PerPrimitiveEXT only Input in Fragment and Output in MeshEXT
4. Added Mesh vulkan validation support for following rules:
   VUID-Layer-Layer-07039 VUID-PrimitiveId-PrimitiveId-07040,VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07042,
   VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07048, VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07054,
   VUID-ViewportIndex-ViewportIndex-07060 VUID-StandaloneSpirv-ExecutionModel-07330 VUID-StandaloneSpirv-ExecutionModel-07331
This commit is contained in:
Pankaj Mistry 2024-03-27 11:07:08 -07:00
parent 6761288d39
commit 7e583d0df3
9 changed files with 972 additions and 5 deletions

View File

@ -143,6 +143,11 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec,
return fail(0) << "must be a variable";
}
break;
case spv::Decoration::PerPrimitiveNV:
if (target->opcode() != spv::Op::OpVariable) {
return fail(0) << "must be a memory object declaration";
}
break;
case spv::Decoration::NoPerspective:
case spv::Decoration::Flat:
case spv::Decoration::Patch:
@ -361,6 +366,15 @@ spv_result_t ValidateMemberDecorate(ValidationState_t& _,
<< _.SpvDecorationString(decoration)
<< " cannot be applied to structure members";
}
const auto target_id = inst->GetOperandAs<uint32_t>(0);
const auto target = _.FindDef(target_id);
if (decoration == spv::Decoration::PerPrimitiveNV &&
target->opcode() != spv::Op::OpTypeStruct) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< _.SpvDecorationString(decoration)
<< " must be a memory object declaration";
}
return SPV_SUCCESS;
}

View File

@ -667,6 +667,36 @@ class BuiltInsValidator {
// instruction.
void Update(const Instruction& inst);
uint32_t GetMeshEntryPoint() {
if (mesh_entry_point_ == 0) {
for (const uint32_t entry_point : _.entry_points()) {
// Every entry point from which this function is called needs to have
// Execution Mode DepthReplacing.
const auto* models = _.GetExecutionModels(entry_point);
if (models->find(spv::ExecutionModel::MeshEXT ) != models->end() ||
models->find(spv::ExecutionModel::MeshNV ) != models->end()) {
mesh_entry_point_ = entry_point;
break;
}
}
}
return mesh_entry_point_;
}
bool isMeshInterfaceVar(const Instruction& inst) {
uint32_t mesh_entry_point = GetMeshEntryPoint();
if (!mesh_entry_point) return false;
for (const auto& desc : _.entry_point_descriptions(mesh_entry_point)) {
for (auto interface : desc.interfaces) {
if (inst.id() == interface) {
return true;
}
}
}
return false;
}
ValidationState_t& _;
// Mapping id -> list of rules which validate instruction referencing the
@ -684,7 +714,7 @@ class BuiltInsValidator {
// or to no_entry_points_. The pointer is guaranteed to never be null.
const std::vector<uint32_t> no_entry_points;
const std::vector<uint32_t>* entry_points_ = &no_entry_points;
uint32_t mesh_entry_point_ = 0;
// Execution models with which the current function can be called.
std::set<spv::ExecutionModel> execution_models_;
};
@ -2146,6 +2176,28 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition(
return error;
}
}
if (isMeshInterfaceVar(inst)) {
if (_.HasCapability(spv::Capability::MeshShadingEXT) &&
!_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(7040)
<< "According to the Vulkan spec the variable decorated with "
"Builtin PrimitiveId within the MeshEXT Execution Model must "
"also be decorated with the PerPrimitiveEXT decoration. ";
}
#if 0
const spv::StorageClass storage_class =
inst.GetOperandAs<spv::StorageClass>(2);
if (storage_class != spv::StorageClass::Output) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(4336)
<< "According to the Vulkan spec the variable decorated with "
"Builtin PrimitiveId within the MeshEXT Execution Model must "
"must be declared using the Output Storage Class. ";
}
#endif
}
}
// Seed at reference checks with this built-in.
@ -2753,6 +2805,21 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition(
return error;
}
}
if (isMeshInterfaceVar(inst) &&
_.HasCapability(spv::Capability::MeshShadingEXT) &&
!_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
uint32_t vkerrid = (label == spv::BuiltIn::Layer) ? 7039 : 7060;
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vkerrid)
<< "According to the Vulkan spec the variable decorated with "
"Builtin "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " within the MeshEXT Execution Model must also be decorated "
"with the PerPrimitiveEXT decoration. ";
}
}
// Seed at reference checks with this built-in.
@ -3458,6 +3525,7 @@ spv_result_t BuiltInsValidator::ValidateViewIndexAtReference(
referenced_from_inst, execution_model);
}
}
}
if (function_id_ == 0) {
@ -4167,6 +4235,23 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
uint32_t mesh_entry_point = GetMeshEntryPoint();
assert(mesh_entry_point);
bool execution_mode_OuputPoints = false;
bool execution_mode_OutputLinesEXT = false;
bool execution_mode_OutputTrianglesEXT = false;
const auto* modes = _.GetExecutionModes(mesh_entry_point);
if (modes->find(spv::ExecutionMode::OutputPoints) != modes->end()) {
execution_mode_OuputPoints = true;
}
if (modes->find(spv::ExecutionMode::OutputLinesEXT) != modes->end()) {
execution_mode_OutputLinesEXT = true;
}
if (modes->find(spv::ExecutionMode::OutputTrianglesEXT) !=
modes->end()) {
execution_mode_OutputTrianglesEXT = true;
}
const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) {
@ -4185,6 +4270,12 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
})) {
return error;
}
if (!execution_mode_OuputPoints) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(7042)
<< "The PrimitivePointIndicesEXT decoration must be used with "
"the OutputPoints Execution Mode";
}
}
if (builtin == spv::BuiltIn::PrimitiveLineIndicesEXT) {
if (spv_result_t error = ValidateArrayedI32Vec(
@ -4203,6 +4294,12 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
})) {
return error;
}
if (!execution_mode_OutputLinesEXT) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(7048)
<< "The PrimitiveLineIndicesEXT decoration must be used with "
"the OutputLinesEXT Execution Mode";
}
}
if (builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT) {
if (spv_result_t error = ValidateArrayedI32Vec(
@ -4221,6 +4318,12 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
})) {
return error;
}
if (!execution_mode_OutputTrianglesEXT) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(7054)
<< "The PrimitiveTriangleIndicesEXT decoration must be used with "
"the OutputTrianglesEXT Execution Mode";
}
}
}
// Seed at reference checks with this built-in.
@ -4249,7 +4352,6 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
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);

View File

@ -767,6 +767,7 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
int num_workgroup_variables = 0;
int num_workgroup_variables_with_block = 0;
int num_workgroup_variables_with_aliased = 0;
bool has_task_payload = false;
for (const auto& desc : descs) {
std::unordered_set<Instruction*> seen_vars;
for (auto interface : desc.interfaces) {
@ -779,6 +780,19 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
}
const spv::StorageClass storage_class =
var_instr->GetOperandAs<spv::StorageClass>(2);
if (vstate.version() >= SPV_SPIRV_VERSION_WORD(1, 5)) {
// SPV_EXT_mesh_shader, at most one task payload is permitted
// per entry point
if (storage_class == spv::StorageClass::TaskPayloadWorkgroupEXT) {
if (has_task_payload) {
return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
<< "There can be at most one OpVariable with storage "
"class TaskPayloadWorkgroupEXT associated with "
"an OpEntryPoint";
}
has_task_payload = true;
}
}
if (vstate.version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
// Starting in 1.4, OpEntryPoint must list all global variables
// it statically uses and those interfaces must be unique.

View File

@ -15,6 +15,7 @@
// Validates ray query instructions from SPV_KHR_ray_query
#include "source/opcode.h"
#include "source/spirv_target_env.h"
#include "source/val/instruction.h"
#include "source/val/validate.h"
#include "source/val/validation_state.h"
@ -22,6 +23,24 @@
namespace spvtools {
namespace val {
bool IsInterfaceVariable(ValidationState_t& _, const Instruction* inst,
spv::ExecutionModel model) {
bool foundInterface = false;
for (auto entry_point : _.entry_points()) {
const auto* models = _.GetExecutionModels(entry_point);
if (models->find(model) == models->end()) return false;
for (const auto& desc : _.entry_point_descriptions(entry_point)) {
for (auto interface : desc.interfaces) {
if (inst->id() == interface) {
foundInterface = true;
break;
}
}
}
}
return foundInterface;
}
spv_result_t MeshShadingPass(ValidationState_t& _, const Instruction* inst) {
const spv::Op opcode = inst->opcode();
switch (opcode) {
@ -103,7 +122,7 @@ spv_result_t MeshShadingPass(ValidationState_t& _, const Instruction* inst) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Primitive Count must be a 32-bit unsigned int scalar";
}
break;
}
@ -111,7 +130,40 @@ spv_result_t MeshShadingPass(ValidationState_t& _, const Instruction* inst) {
// No validation rules (for the moment).
break;
}
case spv::Op::OpVariable: {
if (_.HasCapability(spv::Capability::MeshShadingEXT)) {
bool meshInterfaceVar = IsInterfaceVariable(
_, inst, spv::ExecutionModel::MeshEXT);
bool fragInterfaceVar = IsInterfaceVariable(
_, inst, spv::ExecutionModel::Fragment);
const spv::StorageClass storage_class =
inst->GetOperandAs<spv::StorageClass>(2);
bool storage_output = (storage_class == spv::StorageClass::Output);
bool storage_input = (storage_class == spv::StorageClass::Input);
if (_.HasDecoration(inst->id(), spv::Decoration::PerPrimitiveEXT)) {
if (fragInterfaceVar && !storage_input) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "PerPrimitiveEXT decoration must be applied only to "
"variables in the Input Storage Class in the Fragment "
"Execution Model.";
}
if (meshInterfaceVar && !storage_output) {
std::string vkerror = (spvIsVulkanEnv(_.context()->target_env))
? _.VkErrorID(4336)
: "";
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< vkerror
<< "PerPrimitiveEXT decoration must be applied only to "
"variables in the Output Storage Class in the "
"Storage Class in the MeshEXT Execution Model.";
}
}
}
break;
}
default:
break;
}

View File

@ -543,6 +543,15 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
"tessellation execution model.";
}
}
if (spvIsVulkanEnv(_.context()->target_env)) {
if (_.HasCapability(spv::Capability::MeshShadingEXT) &&
inst->GetOperandAs<uint32_t>(2) == 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(7330)
<< "In mesh shaders using the MeshEXT Execution Model the "
"OutputVertices Execution Mode must be greater than 0";
}
}
break;
case spv::ExecutionMode::OutputLinesEXT:
case spv::ExecutionMode::OutputTrianglesEXT:
@ -557,6 +566,16 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
"execution "
"model.";
}
if (mode == spv::ExecutionMode::OutputPrimitivesEXT &&
spvIsVulkanEnv(_.context()->target_env)) {
if (_.HasCapability(spv::Capability::MeshShadingEXT) &&
inst->GetOperandAs<uint32_t>(2) == 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(7331)
<< "In mesh shaders using the MeshEXT Execution Model the "
"OutputPrimitivesEXT Execution Mode must be greater than 0";
}
}
break;
case spv::ExecutionMode::QuadDerivativesKHR:
if (!std::all_of(models->begin(), models->end(),

View File

@ -1985,6 +1985,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04330);
case 4334:
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
case 4336:
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04336);
case 4337:
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
case 4345:
@ -2311,30 +2313,46 @@ 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 7039:
return VUID_WRAP(VUID-Layer-Layer-07039);
case 7040:
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-07040);
case 7041:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041);
case 7042:
return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07042);
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 7048:
return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07048);
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 7054:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07054);
case 7055:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055);
case 7056:
return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056);
case 7060:
return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-07060);
case 7102:
return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102);
case 7320:
return VUID_WRAP(VUID-StandaloneSpirv-ExecutionModel-07320);
case 7290:
return VUID_WRAP(VUID-StandaloneSpirv-Input-07290);
case 7320:
return VUID_WRAP(VUID-StandaloneSpirv-ExecutionModel-07320);
case 7330:
return VUID_WRAP(VUID-StandaloneSpirv-ExecutionModel-07330);
case 7331:
return VUID_WRAP(VUID-StandaloneSpirv-ExecutionModel-07331);
case 7650:
return VUID_WRAP(VUID-StandaloneSpirv-Base-07650);
case 7651:

View File

@ -4325,6 +4325,29 @@ TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTSuccess) {
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTInvalidExecutionMode) {
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",
"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-PrimitiveTriangleIndicesEXT-"
"PrimitiveTriangleIndicesEXT-07054"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTStorageClass) {
const std::string declarations = R"(
%array = OpTypeArray %v3uint %uint_16
@ -4408,6 +4431,29 @@ TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTSuccess) {
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTInvalidExecutionMode) {
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", "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-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07048"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTStorageClass) {
const std::string declarations = R"(
%array = OpTypeArray %v2uint %uint_16
@ -4471,6 +4517,28 @@ TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTSuccess) {
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTInvalidExecutionMode) {
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", "OutputTrianglesNV",
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-07042"));
}
TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTStorageClass) {
const std::string declarations = R"(
%array = OpTypeArray %uint %uint_16
@ -4515,6 +4583,192 @@ TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTType) {
AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044"));
}
TEST_F(ValidateBuiltIns, VulkanBuiltinPrimtiveIDWithPerPrimitiveEXT) {
const std::string text = R"(
OpCapability MeshShadingEXT
OpCapability Shader
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %MainMesh "MainMesh" %gl_PrimitiveID
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputVertices 3
OpExecutionMode %MainMesh OutputTrianglesNV
OpExecutionMode %MainMesh LocalSize 1 1 1
OpSource Slang 1
OpName %MainMesh "MainMesh"
OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId
OpDecorate %gl_PrimitiveID PerPrimitiveNV
%void = OpTypeVoid
%9 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%int_3 = OpConstant %int 3
%_ptr_Output_v4float = OpTypePointer Output %v4float
%uint_0 = OpConstant %uint 0
%v3float = OpTypeVector %float 3
%_ptr_Output_v3float = OpTypePointer Output %v3float
%v3uint = OpTypeVector %uint 3
%_ptr_Output_v3uint = OpTypePointer Output %v3uint
%_ptr_Output_int = OpTypePointer Output %int
%_arr_int_int_1 = OpTypeArray %int %int_1
%_ptr_Output__arr_int_int_1 = OpTypePointer Output %_arr_int_int_1
%gl_PrimitiveID = OpVariable %_ptr_Output__arr_int_int_1 Output
%MainMesh = OpFunction %void None %9
%25 = OpLabel
OpSetMeshOutputsEXT %uint_3 %uint_1
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
}
TEST_F(ValidateBuiltIns, BadVulkanBuiltinPrimtiveIDWithPerPrimitiveEXT) {
const std::string text = R"(
OpCapability MeshShadingEXT
OpCapability Shader
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %MainMesh "MainMesh" %gl_PrimitiveID
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputVertices 3
OpExecutionMode %MainMesh OutputTrianglesNV
OpExecutionMode %MainMesh LocalSize 1 1 1
OpSource Slang 1
OpName %MainMesh "MainMesh"
OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId
%void = OpTypeVoid
%9 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%int_3 = OpConstant %int 3
%_ptr_Output_v4float = OpTypePointer Output %v4float
%uint_0 = OpConstant %uint 0
%v3float = OpTypeVector %float 3
%_ptr_Output_v3float = OpTypePointer Output %v3float
%v3uint = OpTypeVector %uint 3
%_ptr_Output_v3uint = OpTypePointer Output %v3uint
%_ptr_Output_int = OpTypePointer Output %int
%_arr_int_int_1 = OpTypeArray %int %int_1
%_ptr_Output__arr_int_int_1 = OpTypePointer Output %_arr_int_int_1
%gl_PrimitiveID = OpVariable %_ptr_Output__arr_int_int_1 Output
%MainMesh = OpFunction %void None %9
%25 = OpLabel
OpSetMeshOutputsEXT %uint_3 %uint_1
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-PrimitiveId-PrimitiveId-07040"));
}
TEST_F(ValidateBuiltIns, BadVulkanBuiltinLayerWithPerPrimitiveEXT) {
const std::string text = R"(
OpCapability MeshShadingEXT
OpCapability Shader
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %MainMesh "MainMesh" %gl_Layer
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputVertices 3
OpExecutionMode %MainMesh OutputTrianglesNV
OpExecutionMode %MainMesh LocalSize 1 1 1
OpSource Slang 1
OpName %MainMesh "MainMesh"
OpDecorate %gl_Layer BuiltIn Layer
%void = OpTypeVoid
%9 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%int_3 = OpConstant %int 3
%uint_0 = OpConstant %uint 0
%v3float = OpTypeVector %float 3
%_ptr_Output_v3float = OpTypePointer Output %v3float
%v3uint = OpTypeVector %uint 3
%_ptr_Output_v3uint = OpTypePointer Output %v3uint
%_ptr_Output_int = OpTypePointer Output %int
%_arr_int_int_1 = OpTypeArray %int %int_1
%_ptr_Output__arr_int_int_1 = OpTypePointer Output %_arr_int_int_1
%gl_Layer = OpVariable %_ptr_Output__arr_int_int_1 Output
%MainMesh = OpFunction %void None %9
%25 = OpLabel
OpSetMeshOutputsEXT %uint_3 %uint_1
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-Layer-Layer-07039"));
}
TEST_F(ValidateBuiltIns, BadVulkanBuiltinViewportIndexWithPerPrimitiveEXT) {
const std::string text = R"(
OpCapability MeshShadingEXT
OpCapability Shader
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %MainMesh "MainMesh" %gl_ViewportIndex
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputPrimitivesNV 1
OpExecutionMode %MainMesh OutputVertices 3
OpExecutionMode %MainMesh OutputTrianglesNV
OpExecutionMode %MainMesh LocalSize 1 1 1
OpSource Slang 1
OpName %MainMesh "MainMesh"
OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex
%void = OpTypeVoid
%9 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%float = OpTypeFloat 32
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%int_3 = OpConstant %int 3
%uint_0 = OpConstant %uint 0
%v3float = OpTypeVector %float 3
%_ptr_Output_v3float = OpTypePointer Output %v3float
%v3uint = OpTypeVector %uint 3
%_ptr_Output_v3uint = OpTypePointer Output %v3uint
%_ptr_Output_int = OpTypePointer Output %int
%_arr_int_int_1 = OpTypeArray %int %int_1
%_ptr_Output__arr_int_int_1 = OpTypePointer Output %_arr_int_int_1
%gl_ViewportIndex = OpVariable %_ptr_Output__arr_int_int_1 Output
%MainMesh = OpFunction %void None %9
%25 = OpLabel
OpSetMeshOutputsEXT %uint_3 %uint_1
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-ViewportIndex-ViewportIndex-07060"));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -467,6 +467,82 @@ TEST_F(ValidateMeshShading, TaskPayloadWorkgroupBadExecutionModel) {
"TaskEXT and MeshKHR execution model"));
}
TEST_F(ValidateMeshShading, BadMultipleTaskPayloadWorkgroupEXT) {
const std::string body = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint TaskEXT %main "main" %payload %payload1
%void = OpTypeVoid
%func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_TaskPayloadWorkgroupEXT = OpTypePointer TaskPayloadWorkgroupEXT %uint
%payload = OpVariable %_ptr_TaskPayloadWorkgroupEXT TaskPayloadWorkgroupEXT
%payload1 = OpVariable %_ptr_TaskPayloadWorkgroupEXT TaskPayloadWorkgroupEXT
%main = OpFunction %void None %func
%label = OpLabel
%load = OpLoad %uint %payload
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("There can be at most one OpVariable with storage "
"class TaskPayloadWorkgroupEXT associated with "
"an OpEntryPoint"));
}
TEST_F(ValidateMeshShading, TaskPayloadWorkgroupTaskExtExecutionModel) {
const std::string body = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint TaskEXT %main "main" %payload
%void = OpTypeVoid
%func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_TaskPayloadWorkgroupEXT = OpTypePointer TaskPayloadWorkgroupEXT %uint
%payload = OpVariable %_ptr_TaskPayloadWorkgroupEXT TaskPayloadWorkgroupEXT
%main = OpFunction %void None %func
%label = OpLabel
%load = OpLoad %uint %payload
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
}
TEST_F(ValidateMeshShading, TaskPayloadWorkgroupMeshExtExecutionModel) {
const std::string body = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main" %payload
OpExecutionMode %main OutputVertices 1
OpExecutionMode %main OutputPrimitivesEXT 1
OpExecutionMode %main OutputTrianglesEXT
%void = OpTypeVoid
%func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_TaskPayloadWorkgroupEXT = OpTypePointer TaskPayloadWorkgroupEXT %uint
%payload = OpVariable %_ptr_TaskPayloadWorkgroupEXT TaskPayloadWorkgroupEXT
%main = OpFunction %void None %func
%label = OpLabel
%load = OpLoad %uint %payload
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
}
TEST_F(ValidateMeshShading, OpSetMeshOutputsBadVertexCount) {
const std::string body = R"(
OpCapability MeshShadingEXT
@ -598,6 +674,320 @@ TEST_F(ValidateMeshShading, OpEmitMeshTasksZeroSuccess) {
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
}
TEST_F(ValidateMeshShading, BadPerPrimitiveEXTStorageClassInMeshEXT) {
const std::string body = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationID %blk %triangleNormal
OpExecutionMode %main LocalSize 32 1 1
OpExecutionMode %main OutputVertices 81
OpExecutionMode %main OutputPrimitivesNV 32
OpExecutionMode %main OutputTrianglesNV
OpSource GLSL 450
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpName %iid "iid"
OpName %gl_LocalInvocationID "gl_LocalInvocationID"
OpName %myblock "myblock"
OpMemberName %myblock 0 "f"
OpName %blk "blk"
OpName %triangleNormal "triangleNormal"
OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
OpMemberDecorate %myblock 0 PerPrimitiveEXT
OpDecorate %myblock Block
OpDecorate %blk Location 0
OpDecorate %triangleNormal PerPrimitiveEXT
OpDecorate %triangleNormal Location 0
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_Function_uint = OpTypePointer Function %uint
%v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
%uint_0 = OpConstant %uint 0
%_ptr_Input_uint = OpTypePointer Input %uint
%float = OpTypeFloat 32
%myblock = OpTypeStruct %float
%uint_32 = OpConstant %uint 32
%_arr_myblock_uint_32 = OpTypeArray %myblock %uint_32
%_ptr_Output__arr_myblock_uint_32 = OpTypePointer Output %_arr_myblock_uint_32
%blk = OpVariable %_ptr_Output__arr_myblock_uint_32 Output
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%float_11 = OpConstant %float 11
%_ptr_Output_float = OpTypePointer Output %float
%v3float = OpTypeVector %float 3
%_arr_v3float_uint_32 = OpTypeArray %v3float %uint_32
%_ptr_Output__arr_v3float_uint_32 = OpTypePointer Input %_arr_v3float_uint_32
%triangleNormal = OpVariable %_ptr_Output__arr_v3float_uint_32 Input
%33 = OpConstantComposite %v3float %float_11 %float_11 %float_11
%_ptr_Output_v3float = OpTypePointer Output %v3float
%uint_1 = OpConstant %uint 1
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_32 %uint_1 %uint_1
%main = OpFunction %void None %3
%5 = OpLabel
%iid = OpVariable %_ptr_Function_uint Function
%14 = OpAccessChain %_ptr_Input_uint %gl_LocalInvocationID %uint_0
%15 = OpLoad %uint %14
OpStore %iid %15
%22 = OpLoad %uint %iid
%27 = OpAccessChain %_ptr_Output_float %blk %22 %int_0
OpStore %27 %float_11
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("PerPrimitiveEXT decoration must be applied only to "
"variables in the Output Storage Class in the Storage "
"Class in the MeshEXT Execution Model."));
}
TEST_F(ValidateMeshShading, VulkanPerPrimitiveEXTStorageClassInMeshEXT) {
const std::string body = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationID %blk %triangleNormal
OpExecutionMode %main LocalSize 32 1 1
OpExecutionMode %main OutputVertices 81
OpExecutionMode %main OutputPrimitivesNV 32
OpExecutionMode %main OutputTrianglesNV
OpSource GLSL 450
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpName %iid "iid"
OpName %gl_LocalInvocationID "gl_LocalInvocationID"
OpName %myblock "myblock"
OpMemberName %myblock 0 "f"
OpName %blk "blk"
OpName %triangleNormal "triangleNormal"
OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
OpMemberDecorate %myblock 0 PerPrimitiveEXT
OpDecorate %myblock Block
OpDecorate %blk Location 0
OpDecorate %triangleNormal PerPrimitiveEXT
OpDecorate %triangleNormal Location 0
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_Function_uint = OpTypePointer Function %uint
%v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
%uint_0 = OpConstant %uint 0
%_ptr_Input_uint = OpTypePointer Input %uint
%float = OpTypeFloat 32
%myblock = OpTypeStruct %float
%uint_32 = OpConstant %uint 32
%_arr_myblock_uint_32 = OpTypeArray %myblock %uint_32
%_ptr_Output__arr_myblock_uint_32 = OpTypePointer Output %_arr_myblock_uint_32
%blk = OpVariable %_ptr_Output__arr_myblock_uint_32 Output
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%float_11 = OpConstant %float 11
%_ptr_Output_float = OpTypePointer Output %float
%v3float = OpTypeVector %float 3
%_arr_v3float_uint_32 = OpTypeArray %v3float %uint_32
%_ptr_Output__arr_v3float_uint_32 = OpTypePointer Input %_arr_v3float_uint_32
%triangleNormal = OpVariable %_ptr_Output__arr_v3float_uint_32 Input
%33 = OpConstantComposite %v3float %float_11 %float_11 %float_11
%_ptr_Output_v3float = OpTypePointer Output %v3float
%uint_1 = OpConstant %uint 1
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_32 %uint_1 %uint_1
%main = OpFunction %void None %3
%5 = OpLabel
%iid = OpVariable %_ptr_Function_uint Function
%14 = OpAccessChain %_ptr_Input_uint %gl_LocalInvocationID %uint_0
%15 = OpLoad %uint %14
OpStore %iid %15
%22 = OpLoad %uint %iid
%27 = OpAccessChain %_ptr_Output_float %blk %22 %int_0
OpStore %27 %float_11
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_VULKAN_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(
getDiagnosticString(),
AnyVUID("VUID-PrimitiveId-PrimitiveId-04336"));
}
TEST_F(ValidateMeshShading, BadPerPrimitiveEXTStorageClassInFrag) {
const std::string body = R"(
OpCapability Shader
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %triangleNormal
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpName %triangleNormal "triangleNormal"
OpDecorate %triangleNormal PerPrimitiveNV
OpDecorate %triangleNormal Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3
%_ptr_Input__arr_v3float_uint_3 = OpTypePointer Output %_arr_v3float_uint_3
%triangleNormal = OpVariable %_ptr_Input__arr_v3float_uint_3 Output
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Input_v3float = OpTypePointer Input %v3float
%main = OpFunction %void None %3
%5 = OpLabel
%18 = OpAccessChain %_ptr_Input_v3float %triangleNormal %int_0
%19 = OpLoad %v3float %18
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("PerPrimitiveEXT decoration must be applied only to "
"variables in the Input Storage Class in the Fragment "
"Execution Model."));
}
TEST_F(ValidateMeshShading, PerPrimitiveEXTStorageClassInFrag) {
const std::string body = R"(
OpCapability Shader
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %res3 %triangleNormal
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpName %res3 "res3"
OpName %triangleNormal "triangleNormal"
OpDecorate %res3 Location 0
OpDecorate %triangleNormal PerPrimitiveNV
OpDecorate %triangleNormal Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%_ptr_Output_v3float = OpTypePointer Output %v3float
%res3 = OpVariable %_ptr_Output_v3float Output
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3
%_ptr_Input__arr_v3float_uint_3 = OpTypePointer Input %_arr_v3float_uint_3
%triangleNormal = OpVariable %_ptr_Input__arr_v3float_uint_3 Input
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Input_v3float = OpTypePointer Input %v3float
%main = OpFunction %void None %3
%5 = OpLabel
%18 = OpAccessChain %_ptr_Input_v3float %triangleNormal %int_0
%19 = OpLoad %v3float %18
OpStore %res3 %19
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
}
TEST_F(ValidateMeshShading, PerPrimitiveEXTStorageClassInMeshEXT) {
const std::string body = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationID %blk %triangleNormal
OpExecutionMode %main LocalSize 32 1 1
OpExecutionMode %main OutputVertices 81
OpExecutionMode %main OutputPrimitivesNV 32
OpExecutionMode %main OutputTrianglesNV
OpSource GLSL 450
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpName %iid "iid"
OpName %gl_LocalInvocationID "gl_LocalInvocationID"
OpName %myblock "myblock"
OpMemberName %myblock 0 "f"
OpName %blk "blk"
OpName %triangleNormal "triangleNormal"
OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
OpMemberDecorate %myblock 0 PerPrimitiveNV
OpDecorate %myblock Block
OpDecorate %blk Location 0
OpDecorate %triangleNormal PerPrimitiveNV
OpDecorate %triangleNormal Location 0
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_Function_uint = OpTypePointer Function %uint
%v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
%uint_0 = OpConstant %uint 0
%_ptr_Input_uint = OpTypePointer Input %uint
%float = OpTypeFloat 32
%myblock = OpTypeStruct %float
%uint_32 = OpConstant %uint 32
%_arr_myblock_uint_32 = OpTypeArray %myblock %uint_32
%_ptr_Output__arr_myblock_uint_32 = OpTypePointer Output %_arr_myblock_uint_32
%blk = OpVariable %_ptr_Output__arr_myblock_uint_32 Output
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%float_11 = OpConstant %float 11
%_ptr_Output_float = OpTypePointer Output %float
%v3float = OpTypeVector %float 3
%_arr_v3float_uint_32 = OpTypeArray %v3float %uint_32
%_ptr_Output__arr_v3float_uint_32 = OpTypePointer Output %_arr_v3float_uint_32
%triangleNormal = OpVariable %_ptr_Output__arr_v3float_uint_32 Output
%33 = OpConstantComposite %v3float %float_11 %float_11 %float_11
%_ptr_Output_v3float = OpTypePointer Output %v3float
%uint_1 = OpConstant %uint 1
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_32 %uint_1 %uint_1
%main = OpFunction %void None %3
%5 = OpLabel
%iid = OpVariable %_ptr_Function_uint Function
%14 = OpAccessChain %_ptr_Input_uint %gl_LocalInvocationID %uint_0
%15 = OpLoad %uint %14
OpStore %iid %15
%22 = OpLoad %uint %iid
%27 = OpAccessChain %_ptr_Output_float %blk %22 %int_0
OpStore %27 %float_11
%32 = OpLoad %uint %iid
%35 = OpAccessChain %_ptr_Output_v3float %triangleNormal %32
OpStore %35 %33
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -814,6 +814,110 @@ OpExecutionMode %main OutputPoints
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateModeExecution, MeshEXTOutputVertices) {
const std::string spirv = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpExecutionMode %main OutputVertices 3
OpExecutionMode %main OutputPrimitivesNV 1
OpExecutionMode %main OutputTrianglesNV
OpSource GLSL 460
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%v3uint = OpTypeVector %uint 3
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
%main = OpFunction %void None %3
%5 = OpLabel
OpSetMeshOutputsEXT %uint_3 %uint_1
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
}
TEST_F(ValidateModeExecution, VulkanBadMeshEXTOutputVertices) {
const std::string spirv = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpExecutionMode %main OutputVertices 0
OpExecutionMode %main OutputPrimitivesNV 1
OpExecutionMode %main OutputTrianglesNV
OpSource GLSL 460
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%v3uint = OpTypeVector %uint 3
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
%main = OpFunction %void None %3
%5 = OpLabel
OpSetMeshOutputsEXT %uint_3 %uint_1
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-ExecutionModel-07330"));
}
TEST_F(ValidateModeExecution, VulkanBadMeshEXTOutputOutputPrimitivesEXT) {
const std::string spirv = R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpExecutionMode %main OutputVertices 1
OpExecutionMode %main OutputPrimitivesNV 0
OpExecutionMode %main OutputTrianglesNV
OpSource GLSL 460
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main"
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_1 = OpConstant %uint 1
%v3uint = OpTypeVector %uint 3
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
%main = OpFunction %void None %3
%5 = OpLabel
OpSetMeshOutputsEXT %uint_3 %uint_1
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-ExecutionModel-07331"));
}
TEST_F(ValidateModeExecution, MeshNVOutputVertices) {
const std::string spirv = R"(
OpCapability Shader