Skip to content

Commit 144d63c

Browse files
committed
[spirv-val] Add the validation checks for SPV_QCOM_tile_shading
1 parent cc1e6c5 commit 144d63c

File tree

8 files changed

+544
-19
lines changed

8 files changed

+544
-19
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: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,17 +311,82 @@ 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)
316321
<< _.VkErrorID(6426)
317322
<< "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.";
323+
"entry points require either the "
324+
<< (_.HasCapability(spv::Capability::TileShadingQCOM)
325+
? "TileShadingRateQCOM, "
326+
: "")
327+
<< "LocalSize or LocalSizeId execution mode or an object "
328+
"decorated with WorkgroupSize must be specified.";
329+
}
330+
}
331+
332+
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
333+
if (execution_modes) {
334+
if (execution_modes->count(
335+
spv::ExecutionMode::TileShadingRateQCOM) &&
336+
(execution_modes->count(spv::ExecutionMode::LocalSize) ||
337+
execution_modes->count(spv::ExecutionMode::LocalSizeId))) {
338+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
339+
<< "If the TileShadingRateQCOM execution mode is used, "
340+
<< "LocalSize and LocalSizeId must not be specified.";
341+
}
342+
if (execution_modes->count(
343+
spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
344+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
345+
<< "The NonCoherentTileAttachmentQCOM execution mode must "
346+
"not be used in any stage other than fragment.";
347+
}
348+
}
349+
} else {
350+
if (execution_modes &&
351+
execution_modes->count(spv::ExecutionMode::TileShadingRateQCOM)) {
352+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
353+
<< "If the TileShadingRateQCOM execution mode is used, the "
354+
"TileShadingQCOM capability must be enabled.";
321355
}
322356
}
323357
break;
324358
default:
359+
if (execution_modes &&
360+
execution_modes->count(spv::ExecutionMode::TileShadingRateQCOM)) {
361+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
362+
<< "The TileShadingRateQCOM execution mode must not be used "
363+
"in any stage other than compute.";
364+
}
365+
if (execution_model != spv::ExecutionModel::Fragment) {
366+
if (execution_modes &&
367+
execution_modes->count(
368+
spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
369+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
370+
<< "The NonCoherentTileAttachmentQCOM execution mode must "
371+
"not be used in any stage other than fragment.";
372+
}
373+
if (_.HasCapability(spv::Capability::TileShadingQCOM)) {
374+
return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
375+
<< "The TileShadingQCOM capability must not be enabled in "
376+
"any stage other than compute or fragment.";
377+
}
378+
} else {
379+
if (execution_modes &&
380+
execution_modes->count(
381+
spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM)) {
382+
if (!_.HasCapability(spv::Capability::TileShadingQCOM)) {
383+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
384+
<< "If the NonCoherentTileAttachmentReadQCOM execution "
385+
"mode is used, the TileShadingQCOM capability must be "
386+
"enabled.";
387+
}
388+
}
389+
}
325390
break;
326391
}
327392
}
@@ -758,6 +823,14 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
758823
<< "In the Vulkan environment, the PixelCenterInteger execution "
759824
"mode must not be used.";
760825
}
826+
if (mode == spv::ExecutionMode::TileShadingRateQCOM) {
827+
const auto rateX = inst->GetOperandAs<int>(2);
828+
const auto rateY = inst->GetOperandAs<int>(3);
829+
if ((rateX & (rateX - 1)) != 0 || (rateY & (rateY - 1)) != 0)
830+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
831+
<< "The TileShadingRateQCOM execution mode's x and y values "
832+
"must be powers of 2.";
833+
}
761834
}
762835

763836
return SPV_SUCCESS;
@@ -927,7 +1000,7 @@ spv_result_t ValidateDuplicateExecutionModes(ValidationState_t& _) {
9271000
std::set<PerOperandKey> seen_per_operand;
9281001

9291002
const auto lookupMode = [](spv::ExecutionMode mode) -> std::string {
930-
const spvtools::OperandDesc* desc = nullptr;
1003+
spvtools::OperandDesc* desc = nullptr;
9311004
if (spvtools::LookupOperand(SPV_OPERAND_TYPE_EXECUTION_MODE,
9321005
static_cast<uint32_t>(mode),
9331006
&desc) == SPV_SUCCESS) {

source/val/validation_state.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ void ValidationState_t::RegisterCapability(spv::Capability cap) {
368368
if (module_capabilities_.contains(cap)) return;
369369

370370
module_capabilities_.insert(cap);
371-
const spvtools::OperandDesc* desc = nullptr;
371+
spvtools::OperandDesc* desc = nullptr;
372372
if (SPV_SUCCESS == spvtools::LookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
373373
uint32_t(cap), &desc)) {
374374
for (auto capability : CapabilitySet(desc->capabilities_range.count(),
@@ -1883,6 +1883,7 @@ bool ValidationState_t::IsValidStorageClass(
18831883
case spv::StorageClass::HitObjectAttributeNV:
18841884
case spv::StorageClass::TileImageEXT:
18851885
case spv::StorageClass::NodePayloadAMDX:
1886+
case spv::StorageClass::TileAttachmentQCOM:
18861887
return true;
18871888
default:
18881889
return false;

test/val/val_capability_test.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,7 +2375,7 @@ spv_result_t spvCoreOperandTableNameLookup(spv_target_env env,
23752375
const size_t nameLength) {
23762376
if (!name) return SPV_ERROR_INVALID_POINTER;
23772377

2378-
const spvtools::OperandDesc* entry = nullptr;
2378+
spvtools::OperandDesc* entry = nullptr;
23792379
if (SPV_SUCCESS == spvtools::LookupOperand(type, name, nameLength, &entry)) {
23802380
// Check for min version only.
23812381
if (spvVersionForTargetEnv(env) >= entry->minVersion) {
@@ -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)