Skip to content

Commit 0102146

Browse files
authored
[spirv-val] Add the validation checks for SPV_QCOM_tile_shading (#6130)
* Adding the QCOM tile shading support
1 parent 736e415 commit 0102146

8 files changed

+546
-17
lines changed

source/val/validate_annotation.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec,
233233
case spv::Decoration::DescriptorSet:
234234
if (sc != spv::StorageClass::StorageBuffer &&
235235
sc != spv::StorageClass::Uniform &&
236-
sc != spv::StorageClass::UniformConstant) {
236+
sc != spv::StorageClass::UniformConstant &&
237+
sc != spv::StorageClass::TileAttachmentQCOM) {
237238
return fail(6491) << "must be in the StorageBuffer, Uniform, or "
238239
"UniformConstant storage class";
239240
}

source/val/validate_decorations.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,7 @@ bool IsAlignedTo(uint32_t offset, uint32_t alignment) {
404404
// or row major-ness.
405405
spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
406406
const char* decoration_str, bool blockRules,
407-
bool scalar_block_layout,
408-
uint32_t incoming_offset,
407+
bool scalar_block_layout, uint32_t incoming_offset,
409408
MemberConstraints& constraints,
410409
ValidationState_t& vstate) {
411410
if (vstate.options()->skip_block_layout) return SPV_SUCCESS;
@@ -1023,7 +1022,7 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
10231022
}
10241023
if (num_workgroup_variables_with_block > 1 &&
10251024
num_workgroup_variables_with_block !=
1026-
num_workgroup_variables_with_aliased) {
1025+
num_workgroup_variables_with_aliased) {
10271026
return vstate.diag(SPV_ERROR_INVALID_BINARY,
10281027
vstate.FindDef(entry_point))
10291028
<< "When declaring WorkgroupMemoryExplicitLayoutKHR, "
@@ -1246,10 +1245,10 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
12461245
}
12471246
// Prepare for messages
12481247
const char* sc_str =
1249-
uniform ? "Uniform"
1250-
: (push_constant ? "PushConstant"
1251-
: (workgroup ? "Workgroup"
1252-
: "StorageBuffer"));
1248+
uniform
1249+
? "Uniform"
1250+
: (push_constant ? "PushConstant"
1251+
: (workgroup ? "Workgroup" : "StorageBuffer"));
12531252

12541253
if (spvIsVulkanEnv(vstate.context()->target_env)) {
12551254
const bool block = hasDecoration(id, spv::Decoration::Block, vstate);
@@ -1765,6 +1764,7 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate,
17651764
var_storage_class == spv::StorageClass::Private) &&
17661765
vstate.features().nonwritable_var_in_function_or_private) {
17671766
// New permitted feature in SPIR-V 1.4.
1767+
} else if (var_storage_class == spv::StorageClass::TileAttachmentQCOM) {
17681768
} else if (
17691769
// It may point to a UBO, SSBO, storage image, or raw access chain.
17701770
vstate.IsPointerToUniformBlock(type_id) ||
@@ -2030,7 +2030,8 @@ spv_result_t CheckRelaxPrecisionDecoration(ValidationState_t& vstate,
20302030
{ \
20312031
spv_result_t e##LINE = (X); \
20322032
if (e##LINE != SPV_SUCCESS) return e##LINE; \
2033-
} static_assert(true, "require extra semicolon")
2033+
} \
2034+
static_assert(true, "require extra semicolon")
20342035
#define PASS_OR_BAIL(X) PASS_OR_BAIL_AT_LINE(X, __LINE__)
20352036

20362037
// Check rules for decorations where we start from the decoration rather

source/val/validate_memory.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,65 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
937937
}
938938
}
939939

940+
if (_.HasCapability(spv::Capability::TileShadingQCOM) &&
941+
storage_class == spv::StorageClass::TileAttachmentQCOM) {
942+
if (result_type->opcode() == spv::Op::OpTypePointer) {
943+
const auto pointee_type =
944+
_.FindDef(result_type->GetOperandAs<uint32_t>(2));
945+
if (pointee_type && pointee_type->opcode() == spv::Op::OpTypeImage) {
946+
spv::Dim dim = static_cast<spv::Dim>(pointee_type->word(3));
947+
if (dim != spv::Dim::Dim2D) {
948+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
949+
<< "Any OpTypeImage variable in the TileAttachmentQCOM "
950+
"Storage Class must "
951+
"have 2D as its dimension";
952+
}
953+
unsigned sampled = pointee_type->word(7);
954+
if (sampled != 1 && sampled != 2) {
955+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
956+
<< "Any OpyTpeImage variable in the TileAttachmentQCOM "
957+
"Storage Class must "
958+
"have 1 or 2 as Image 'Sampled' parameter";
959+
}
960+
for (const auto& pair_o : inst->uses()) {
961+
const auto* use_inst_o = pair_o.first;
962+
if (use_inst_o->opcode() == spv::Op::OpLoad) {
963+
for (const auto& pair_i : use_inst_o->uses()) {
964+
const auto* use_inst_i = pair_i.first;
965+
switch (use_inst_i->opcode()) {
966+
case spv::Op::OpImageQueryFormat:
967+
case spv::Op::OpImageQueryOrder:
968+
case spv::Op::OpImageQuerySizeLod:
969+
case spv::Op::OpImageQuerySize:
970+
case spv::Op::OpImageQueryLod:
971+
case spv::Op::OpImageQueryLevels:
972+
case spv::Op::OpImageQuerySamples:
973+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
974+
<< "Any variable in the TileAttachmentQCOM Storage "
975+
"Class must "
976+
"not be consumed by an OpImageQuery* instruction";
977+
default:
978+
break;
979+
}
980+
}
981+
}
982+
}
983+
}
984+
}
985+
986+
if (!(_.HasDecoration(inst->id(), spv::Decoration::DescriptorSet) &&
987+
_.HasDecoration(inst->id(), spv::Decoration::Binding))) {
988+
return _.diag(SPV_ERROR_INVALID_ID, inst)
989+
<< "Any variable in the TileAttachmentQCOM Storage Class must "
990+
"be decorated with DescriptorSet and Binding";
991+
}
992+
if (_.HasDecoration(inst->id(), spv::Decoration::Component)) {
993+
return _.diag(SPV_ERROR_INVALID_ID, inst)
994+
<< "Any variable in the TileAttachmentQCOM Storage Class must "
995+
"not be decorated with Component decoration";
996+
}
997+
}
998+
940999
return SPV_SUCCESS;
9411000
}
9421001

source/val/validate_mode_setting.cpp

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,17 +311,84 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
311311
}
312312
}
313313
}
314+
if (!ok && _.HasCapability(spv::Capability::TileShadingQCOM)) {
315+
ok =
316+
execution_modes &&
317+
execution_modes->count(spv::ExecutionMode::TileShadingRateQCOM);
318+
}
314319
if (!ok) {
315320
return _.diag(SPV_ERROR_INVALID_DATA, inst)
316-
<< _.VkErrorID(6426)
321+
<< (_.HasCapability(spv::Capability::TileShadingQCOM)
322+
? _.VkErrorID(10685)
323+
: _.VkErrorID(6426))
317324
<< "In the Vulkan environment, GLCompute execution model "
318-
"entry points require either the LocalSize or "
319-
"LocalSizeId execution mode or an object decorated with "
320-
"WorkgroupSize must be specified.";
325+
"entry points require either the "
326+
<< (_.HasCapability(spv::Capability::TileShadingQCOM)
327+
? "TileShadingRateQCOM, "
328+
: "")
329+
<< "LocalSize or LocalSizeId execution mode or an object "
330+
"decorated with WorkgroupSize must be specified.";
331+
}
332+
}
333+
334+
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
335+
if (execution_modes) {
336+
if (execution_modes->count(
337+
spv::ExecutionMode::TileShadingRateQCOM) &&
338+
(execution_modes->count(spv::ExecutionMode::LocalSize) ||
339+
execution_modes->count(spv::ExecutionMode::LocalSizeId))) {
340+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
341+
<< "If the TileShadingRateQCOM execution mode is used, "
342+
<< "LocalSize and LocalSizeId must not be specified.";
343+
}
344+
if (execution_modes->count(
345+
spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
346+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
347+
<< "The NonCoherentTileAttachmentQCOM execution mode must "
348+
"not be used in any stage other than fragment.";
349+
}
350+
}
351+
} else {
352+
if (execution_modes &&
353+
execution_modes->count(spv::ExecutionMode::TileShadingRateQCOM)) {
354+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
355+
<< "If the TileShadingRateQCOM execution mode is used, the "
356+
"TileShadingQCOM capability must be enabled.";
321357
}
322358
}
323359
break;
324360
default:
361+
if (execution_modes &&
362+
execution_modes->count(spv::ExecutionMode::TileShadingRateQCOM)) {
363+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
364+
<< "The TileShadingRateQCOM execution mode must not be used "
365+
"in any stage other than compute.";
366+
}
367+
if (execution_model != spv::ExecutionModel::Fragment) {
368+
if (execution_modes &&
369+
execution_modes->count(
370+
spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
371+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
372+
<< "The NonCoherentTileAttachmentQCOM execution mode must "
373+
"not be used in any stage other than fragment.";
374+
}
375+
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
376+
return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
377+
<< "The TileShadingQCOM capability must not be enabled in "
378+
"any stage other than compute or fragment.";
379+
}
380+
} else {
381+
if (execution_modes &&
382+
execution_modes->count(
383+
spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
384+
if (!_.HasCapability(spv::Capability::TileShadingQCOM)) {
385+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
386+
<< "If the NonCoherentTileAttachmentReadQCOM execution "
387+
"mode is used, the TileShadingQCOM capability must be "
388+
"enabled.";
389+
}
390+
}
391+
}
325392
break;
326393
}
327394
}
@@ -758,6 +825,14 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
758825
<< "In the Vulkan environment, the PixelCenterInteger execution "
759826
"mode must not be used.";
760827
}
828+
if (mode == spv::ExecutionMode::TileShadingRateQCOM) {
829+
const auto rateX = inst->GetOperandAs<int>(2);
830+
const auto rateY = inst->GetOperandAs<int>(3);
831+
if ((rateX & (rateX - 1)) != 0 || (rateY & (rateY - 1)) != 0)
832+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
833+
<< "The TileShadingRateQCOM execution mode's x and y values "
834+
"must be powers of 2.";
835+
}
761836
}
762837

763838
return SPV_SUCCESS;

source/val/validation_state.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,7 @@ bool ValidationState_t::IsValidStorageClass(
19041904
case spv::StorageClass::HitObjectAttributeNV:
19051905
case spv::StorageClass::TileImageEXT:
19061906
case spv::StorageClass::NodePayloadAMDX:
1907+
case spv::StorageClass::TileAttachmentQCOM:
19071908
return true;
19081909
default:
19091910
return false;
@@ -2594,6 +2595,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
25942595
return VUID_WRAP(VUID-StandaloneSpirv-Component-10583);
25952596
case 10684:
25962597
return VUID_WRAP(VUID-StandaloneSpirv-None-10684);
2598+
case 10685:
2599+
return VUID_WRAP(VUID-StandaloneSpirv-None-10685);
25972600
default:
25982601
return ""; // unknown id
25992602
}

test/val/val_capability_test.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3214,7 +3214,8 @@ std::string MinimalShaderModuleWithCapability(std::string cap) {
32143214
: "";
32153215
return std::string("OpCapability ") + cap + extra_cap + R"(
32163216
OpCapability Shader
3217-
OpMemoryModel Logical )" + mem_model + R"(
3217+
OpMemoryModel Logical )" +
3218+
mem_model + R"(
32183219
OpEntryPoint Vertex %main "main"
32193220
%void = OpTypeVoid
32203221
%void_fn = OpTypeFunction %void
@@ -3383,6 +3384,23 @@ OpMemoryModel Logical GLSL450
33833384
"the VulkanMemoryModel capability must also be declared"));
33843385
}
33853386

3387+
TEST_F(ValidateCapability, TileShadingQCOM) {
3388+
const auto spirv = R"(
3389+
OpCapability Shader
3390+
OpCapability TileShadingQCOM
3391+
OpExtension "SPV_QCOM_tile_shading"
3392+
OpMemoryModel Logical GLSL450
3393+
OpEntryPoint Vertex %func "main"
3394+
)" + std::string(kVoidFVoid);
3395+
3396+
spv_target_env env = SPV_ENV_VULKAN_1_4;
3397+
CompileSuccessfully(spirv, env);
3398+
EXPECT_THAT(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(env));
3399+
EXPECT_THAT(getDiagnosticString(),
3400+
HasSubstr("The TileShadingQCOM capability must not be enabled "
3401+
"in any stage other than compute or fragment"));
3402+
}
3403+
33863404
} // namespace
33873405
} // namespace val
33883406
} // namespace spvtools

0 commit comments

Comments
 (0)