Skip to content

Commit 66798c8

Browse files
spirv-val: Add Mesh/Task to check for LocalSize (#6459)
obvious oversight of Mesh/Task that is being fixed up in the spec here https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/7901 (update, we approved the spec language, will be out in the 1.4.336 spec)
1 parent a32a82b commit 66798c8

File tree

4 files changed

+178
-65
lines changed

4 files changed

+178
-65
lines changed

source/val/validate_mode_setting.cpp

Lines changed: 107 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,48 @@ namespace spvtools {
2727
namespace val {
2828
namespace {
2929

30+
// TODO - Make a common util if someone else needs it too outside this file
31+
const char* ExecutionModelToString(spv::ExecutionModel value) {
32+
switch (value) {
33+
case spv::ExecutionModel::Vertex:
34+
return "Vertex";
35+
case spv::ExecutionModel::TessellationControl:
36+
return "TessellationControl";
37+
case spv::ExecutionModel::TessellationEvaluation:
38+
return "TessellationEvaluation";
39+
case spv::ExecutionModel::Geometry:
40+
return "Geometry";
41+
case spv::ExecutionModel::Fragment:
42+
return "Fragment";
43+
case spv::ExecutionModel::GLCompute:
44+
return "GLCompute";
45+
case spv::ExecutionModel::Kernel:
46+
return "Kernel";
47+
case spv::ExecutionModel::TaskNV:
48+
return "TaskNV";
49+
case spv::ExecutionModel::MeshNV:
50+
return "MeshNV";
51+
case spv::ExecutionModel::RayGenerationKHR:
52+
return "RayGenerationKHR";
53+
case spv::ExecutionModel::IntersectionKHR:
54+
return "IntersectionKHR";
55+
case spv::ExecutionModel::AnyHitKHR:
56+
return "AnyHitKHR";
57+
case spv::ExecutionModel::ClosestHitKHR:
58+
return "ClosestHitKHR";
59+
case spv::ExecutionModel::MissKHR:
60+
return "MissKHR";
61+
case spv::ExecutionModel::CallableKHR:
62+
return "CallableKHR";
63+
case spv::ExecutionModel::TaskEXT:
64+
return "TaskEXT";
65+
case spv::ExecutionModel::MeshEXT:
66+
return "MeshEXT";
67+
default:
68+
return "Unknown";
69+
}
70+
}
71+
3072
spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
3173
const auto entry_point_id = inst->GetOperandAs<uint32_t>(1);
3274
auto entry_point = _.FindDef(entry_point_id);
@@ -306,74 +348,79 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
306348
}
307349

308350
if (spvIsVulkanEnv(_.context()->target_env)) {
309-
switch (execution_model) {
310-
case spv::ExecutionModel::GLCompute:
311-
if (!has_mode(spv::ExecutionMode::LocalSize)) {
312-
bool ok = has_workgroup_size || has_local_size_id;
313-
if (!ok && _.HasCapability(spv::Capability::TileShadingQCOM)) {
314-
ok = has_mode(spv::ExecutionMode::TileShadingRateQCOM);
315-
}
316-
if (!ok) {
317-
return _.diag(SPV_ERROR_INVALID_DATA, inst)
318-
<< _.VkErrorID(10685)
319-
<< "In the Vulkan environment, GLCompute execution model "
320-
"entry points require either the "
321-
<< (_.HasCapability(spv::Capability::TileShadingQCOM)
322-
? "TileShadingRateQCOM, "
323-
: "")
324-
<< "LocalSize or LocalSizeId execution mode or an object "
325-
"decorated with WorkgroupSize must be specified.";
326-
}
351+
// SPV_QCOM_tile_shading checks
352+
if (execution_model == spv::ExecutionModel::GLCompute) {
353+
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
354+
if (has_mode(spv::ExecutionMode::TileShadingRateQCOM) &&
355+
(has_mode(spv::ExecutionMode::LocalSize) ||
356+
has_mode(spv::ExecutionMode::LocalSizeId))) {
357+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
358+
<< "If the TileShadingRateQCOM execution mode is used, "
359+
<< "LocalSize and LocalSizeId must not be specified.";
327360
}
328-
329-
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
330-
if (has_mode(spv::ExecutionMode::TileShadingRateQCOM) &&
331-
(has_mode(spv::ExecutionMode::LocalSize) ||
332-
has_mode(spv::ExecutionMode::LocalSizeId))) {
333-
return _.diag(SPV_ERROR_INVALID_DATA, inst)
334-
<< "If the TileShadingRateQCOM execution mode is used, "
335-
<< "LocalSize and LocalSizeId must not be specified.";
336-
}
337-
if (has_mode(spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
338-
return _.diag(SPV_ERROR_INVALID_DATA, inst)
339-
<< "The NonCoherentTileAttachmentQCOM execution mode must "
340-
"not be used in any stage other than fragment.";
341-
}
342-
} else {
343-
if (has_mode(spv::ExecutionMode::TileShadingRateQCOM)) {
344-
return _.diag(SPV_ERROR_INVALID_DATA, inst)
345-
<< "If the TileShadingRateQCOM execution mode is used, the "
346-
"TileShadingQCOM capability must be enabled.";
347-
}
361+
if (has_mode(spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
362+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
363+
<< "The NonCoherentTileAttachmentQCOM execution mode must "
364+
"not be used in any stage other than fragment.";
348365
}
349-
break;
350-
default:
366+
} else {
351367
if (has_mode(spv::ExecutionMode::TileShadingRateQCOM)) {
352368
return _.diag(SPV_ERROR_INVALID_DATA, inst)
353-
<< "The TileShadingRateQCOM execution mode must not be used "
354-
"in any stage other than compute.";
369+
<< "If the TileShadingRateQCOM execution mode is used, the "
370+
"TileShadingQCOM capability must be enabled.";
355371
}
356-
if (execution_model != spv::ExecutionModel::Fragment) {
357-
if (has_mode(spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
372+
}
373+
} else {
374+
if (has_mode(spv::ExecutionMode::TileShadingRateQCOM)) {
375+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
376+
<< "The TileShadingRateQCOM execution mode must not be used "
377+
"in any stage other than compute.";
378+
}
379+
if (execution_model != spv::ExecutionModel::Fragment) {
380+
if (has_mode(spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
381+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
382+
<< "The NonCoherentTileAttachmentQCOM execution mode must "
383+
"not be used in any stage other than fragment.";
384+
}
385+
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
386+
return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
387+
<< "The TileShadingQCOM capability must not be enabled in "
388+
"any stage other than compute or fragment.";
389+
}
390+
} else {
391+
if (has_mode(spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
392+
if (!_.HasCapability(spv::Capability::TileShadingQCOM)) {
358393
return _.diag(SPV_ERROR_INVALID_DATA, inst)
359-
<< "The NonCoherentTileAttachmentQCOM execution mode must "
360-
"not be used in any stage other than fragment.";
361-
}
362-
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
363-
return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
364-
<< "The TileShadingQCOM capability must not be enabled in "
365-
"any stage other than compute or fragment.";
366-
}
367-
} else {
368-
if (has_mode(spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
369-
if (!_.HasCapability(spv::Capability::TileShadingQCOM)) {
370-
return _.diag(SPV_ERROR_INVALID_DATA, inst)
371-
<< "If the NonCoherentTileAttachmentReadQCOM execution "
372-
"mode is used, the TileShadingQCOM capability must be "
373-
"enabled.";
374-
}
394+
<< "If the NonCoherentTileAttachmentReadQCOM execution "
395+
"mode is used, the TileShadingQCOM capability must be "
396+
"enabled.";
375397
}
376398
}
399+
}
400+
}
401+
402+
switch (execution_model) {
403+
case spv::ExecutionModel::GLCompute:
404+
case spv::ExecutionModel::MeshEXT:
405+
case spv::ExecutionModel::MeshNV:
406+
case spv::ExecutionModel::TaskEXT:
407+
case spv::ExecutionModel::TaskNV:
408+
if (!has_mode(spv::ExecutionMode::LocalSize) && !has_workgroup_size &&
409+
!has_local_size_id &&
410+
!has_mode(spv::ExecutionMode::TileShadingRateQCOM)) {
411+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
412+
<< _.VkErrorID(10685) << "In the Vulkan environment, "
413+
<< ExecutionModelToString(execution_model)
414+
<< " execution model "
415+
"entry points require either the "
416+
<< (_.HasCapability(spv::Capability::TileShadingQCOM)
417+
? "TileShadingRateQCOM, "
418+
: "")
419+
<< "LocalSize or LocalSizeId execution mode or an object "
420+
"decorated with WorkgroupSize must be specified.";
421+
}
422+
break;
423+
default:
377424
break;
378425
}
379426
}

test/val/val_builtins_test.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,11 @@ CodeGenerator GetInMainCodeGenerator(const char* const built_in,
141141
execution_modes << "OpExecutionMode %" << entry_point.name
142142
<< " OutputPoints\n";
143143
}
144-
if (0 == std::strcmp(execution_model, "GLCompute")) {
144+
if (0 == std::strcmp(execution_model, "GLCompute") ||
145+
0 == std::strcmp(execution_model, "MeshEXT") ||
146+
0 == std::strcmp(execution_model, "MeshNV") ||
147+
0 == std::strcmp(execution_model, "MeshEXT") ||
148+
0 == std::strcmp(execution_model, "TaskNV")) {
145149
execution_modes << "OpExecutionMode %" << entry_point.name
146150
<< " LocalSize 1 1 1\n";
147151
}
@@ -303,7 +307,11 @@ CodeGenerator GetInFunctionCodeGenerator(const char* const built_in,
303307
execution_modes << "OpExecutionMode %" << entry_point.name
304308
<< " OutputPoints\n";
305309
}
306-
if (0 == std::strcmp(execution_model, "GLCompute")) {
310+
if (0 == std::strcmp(execution_model, "GLCompute") ||
311+
0 == std::strcmp(execution_model, "MeshEXT") ||
312+
0 == std::strcmp(execution_model, "MeshNV") ||
313+
0 == std::strcmp(execution_model, "MeshEXT") ||
314+
0 == std::strcmp(execution_model, "TaskNV")) {
307315
execution_modes << "OpExecutionMode %" << entry_point.name
308316
<< " LocalSize 1 1 1\n";
309317
}
@@ -452,7 +460,11 @@ CodeGenerator GetVariableCodeGenerator(const char* const built_in,
452460
execution_modes << "OpExecutionMode %" << entry_point.name
453461
<< " OutputPoints\n";
454462
}
455-
if (0 == std::strcmp(execution_model, "GLCompute")) {
463+
if (0 == std::strcmp(execution_model, "GLCompute") ||
464+
0 == std::strcmp(execution_model, "MeshEXT") ||
465+
0 == std::strcmp(execution_model, "MeshNV") ||
466+
0 == std::strcmp(execution_model, "MeshEXT") ||
467+
0 == std::strcmp(execution_model, "TaskNV")) {
456468
execution_modes << "OpExecutionMode %" << entry_point.name
457469
<< " LocalSize 1 1 1\n";
458470
}
@@ -2703,7 +2715,11 @@ CodeGenerator GetArrayedVariableCodeGenerator(const char* const built_in,
27032715
execution_modes << "OpExecutionMode %" << entry_point.name
27042716
<< " OutputPoints\n";
27052717
}
2706-
if (0 == std::strcmp(execution_model, "GLCompute")) {
2718+
if (0 == std::strcmp(execution_model, "GLCompute") ||
2719+
0 == std::strcmp(execution_model, "MeshEXT") ||
2720+
0 == std::strcmp(execution_model, "MeshNV") ||
2721+
0 == std::strcmp(execution_model, "MeshEXT") ||
2722+
0 == std::strcmp(execution_model, "TaskNV")) {
27072723
execution_modes << "OpExecutionMode %" << entry_point.name
27082724
<< " LocalSize 1 1 1\n";
27092725
}
@@ -3615,6 +3631,7 @@ OpDecorate %gl_ViewportIndex PerPrimitiveNV
36153631
EntryPoint entry_point;
36163632
entry_point.name = "main_d_r";
36173633
entry_point.execution_model = "MeshNV";
3634+
entry_point.execution_modes = "OpExecutionMode %main_d_r LocalSize 1 1 1";
36183635
entry_point.interfaces = "%gl_PrimitiveID %gl_Layer %gl_ViewportIndex";
36193636
generator.entry_points_.push_back(std::move(entry_point));
36203637

@@ -3653,6 +3670,7 @@ OpDecorate %gl_ViewportIndex PerPrimitiveNV
36533670
EntryPoint entry_point;
36543671
entry_point.name = "main_d_r";
36553672
entry_point.execution_model = "MeshNV";
3673+
entry_point.execution_modes = "OpExecutionMode %main_d_r LocalSize 1 1 1";
36563674
entry_point.interfaces = "%gl_PrimitiveID %gl_Layer %gl_ViewportIndex";
36573675
entry_point.body = "%ref_load = OpLoad %_arr_float_uint_81 %gl_PrimitiveID";
36583676
generator.entry_points_.push_back(std::move(entry_point));

test/val/val_mesh_shading_test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ TEST_F(ValidateMeshShading, VulkanBasicMeshAndTaskSuccess) {
234234
OpMemoryModel Logical GLSL450
235235
OpEntryPoint MeshEXT %mainMesh "mainMesh"
236236
OpEntryPoint TaskEXT %mainTask "mainTask"
237+
OpExecutionMode %mainMesh LocalSize 1 1 1
238+
OpExecutionMode %mainTask LocalSize 1 1 1
237239
OpExecutionMode %mainMesh OutputVertices 1
238240
OpExecutionMode %mainMesh OutputPrimitivesEXT 1
239241
OpExecutionMode %mainMesh OutputTrianglesEXT

test/val/val_modes_test.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,53 @@ OpEntryPoint GLCompute %main "main"
7373
"or an object decorated with WorkgroupSize must be specified."));
7474
}
7575

76+
TEST_F(ValidateMode, MeshNoModeVulkan) {
77+
const std::string spirv = R"(
78+
OpCapability Shader
79+
OpCapability MeshShadingEXT
80+
OpExtension "SPV_EXT_mesh_shader"
81+
OpMemoryModel Logical GLSL450
82+
OpEntryPoint MeshEXT %main "main"
83+
OpExecutionMode %main OutputVertices 81
84+
OpExecutionMode %main OutputPrimitivesEXT 16
85+
OpExecutionMode %main OutputPoints
86+
)" + kVoidFunction;
87+
88+
spv_target_env env = SPV_ENV_VULKAN_1_3;
89+
CompileSuccessfully(spirv, env);
90+
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
91+
EXPECT_THAT(getDiagnosticString(),
92+
AnyVUID("VUID-StandaloneSpirv-None-10685"));
93+
EXPECT_THAT(
94+
getDiagnosticString(),
95+
HasSubstr(
96+
"In the Vulkan environment, MeshEXT execution model entry "
97+
"points require either the LocalSize or LocalSizeId execution mode "
98+
"or an object decorated with WorkgroupSize must be specified."));
99+
}
100+
101+
TEST_F(ValidateMode, TaskNoModeVulkan) {
102+
const std::string spirv = R"(
103+
OpCapability Shader
104+
OpCapability MeshShadingEXT
105+
OpExtension "SPV_EXT_mesh_shader"
106+
OpMemoryModel Logical GLSL450
107+
OpEntryPoint TaskEXT %main "main"
108+
)" + kVoidFunction;
109+
110+
spv_target_env env = SPV_ENV_VULKAN_1_3;
111+
CompileSuccessfully(spirv, env);
112+
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
113+
EXPECT_THAT(getDiagnosticString(),
114+
AnyVUID("VUID-StandaloneSpirv-None-10685"));
115+
EXPECT_THAT(
116+
getDiagnosticString(),
117+
HasSubstr(
118+
"In the Vulkan environment, TaskEXT execution model entry "
119+
"points require either the LocalSize or LocalSizeId execution mode "
120+
"or an object decorated with WorkgroupSize must be specified."));
121+
}
122+
76123
TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) {
77124
const std::string spirv = R"(
78125
OpCapability Shader
@@ -2926,7 +2973,6 @@ OpCapability TileShadingQCOM
29262973
OpExtension "SPV_QCOM_tile_shading"
29272974
OpMemoryModel Logical GLSL450
29282975
OpEntryPoint GLCompute %main "main"
2929-
OpExecutionMode %main NonCoherentTileAttachmentReadQCOM
29302976
)" + kVoidFunction;
29312977

29322978
spv_target_env env = SPV_ENV_VULKAN_1_4;

0 commit comments

Comments
 (0)