layers: Add subgroup validation
Change-Id: I33d1c29f95f740f42b9a8d62bf5fd04f0917e870
diff --git a/layers/shader_validation.cpp b/layers/shader_validation.cpp
index 4cd1391..fc3b2c4 100644
--- a/layers/shader_validation.cpp
+++ b/layers/shader_validation.cpp
@@ -1488,6 +1488,18 @@
return ss.str();
}
+static bool RequirePropertyFlag(debug_report_data const *report_data, VkBool32 check, char const *flag, char const *structure) {
+ if (!check) {
+ if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+ kVUID_Core_Shader_ExceedDeviceLimit, "Shader requires flag %s set in %s but it is not set on the device", flag,
+ structure)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static bool RequireFeature(debug_report_data const *report_data, VkBool32 feature, char const *feature_name) {
if (!feature) {
if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
@@ -1511,8 +1523,7 @@
return false;
}
-bool CoreChecks::ValidateShaderCapabilities(SHADER_MODULE_STATE const *src, VkShaderStageFlagBits stage,
- bool has_writable_descriptor) {
+bool CoreChecks::ValidateShaderCapabilities(SHADER_MODULE_STATE const *src, VkShaderStageFlagBits stage) {
bool skip = false;
struct FeaturePointer {
@@ -1700,10 +1711,86 @@
extension_names += "]";
skip |= RequireExtension(report_data, has_ext, extension_names.c_str());
}
+ } else { // Do group non-uniform checks
+ const VkSubgroupFeatureFlags supportedOperations = phys_dev_ext_props.subgroup_props.supportedOperations;
+ const VkSubgroupFeatureFlags supportedStages = phys_dev_ext_props.subgroup_props.supportedStages;
+
+ switch (insn.word(1)) {
+ default:
+ break;
+ case spv::CapabilityGroupNonUniform:
+ case spv::CapabilityGroupNonUniformVote:
+ case spv::CapabilityGroupNonUniformArithmetic:
+ case spv::CapabilityGroupNonUniformBallot:
+ case spv::CapabilityGroupNonUniformShuffle:
+ case spv::CapabilityGroupNonUniformShuffleRelative:
+ case spv::CapabilityGroupNonUniformClustered:
+ case spv::CapabilityGroupNonUniformQuad:
+ case spv::CapabilityGroupNonUniformPartitionedNV:
+ RequirePropertyFlag(report_data, supportedStages & stage, string_VkShaderStageFlagBits(stage),
+ "VkPhysicalDeviceSubgroupProperties::supportedStages");
+ break;
+ }
+
+ switch (insn.word(1)) {
+ default:
+ break;
+ case spv::CapabilityGroupNonUniform:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT,
+ "VK_SUBGROUP_FEATURE_BASIC_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformVote:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT,
+ "VK_SUBGROUP_FEATURE_VOTE_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformArithmetic:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT,
+ "VK_SUBGROUP_FEATURE_ARITHMETIC_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformBallot:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT,
+ "VK_SUBGROUP_FEATURE_BALLOT_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformShuffle:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT,
+ "VK_SUBGROUP_FEATURE_SHUFFLE_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformShuffleRelative:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT,
+ "VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformClustered:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT,
+ "VK_SUBGROUP_FEATURE_CLUSTERED_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformQuad:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT,
+ "VK_SUBGROUP_FEATURE_QUAD_BIT",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ case spv::CapabilityGroupNonUniformPartitionedNV:
+ RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV,
+ "VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV",
+ "VkPhysicalDeviceSubgroupProperties::supportedOperations");
+ break;
+ }
}
}
}
+ return skip;
+}
+
+bool CoreChecks::ValidateShaderStageWritableDescriptor(VkShaderStageFlagBits stage, bool has_writable_descriptor) {
+ bool skip = false;
+
if (has_writable_descriptor) {
switch (stage) {
case VK_SHADER_STAGE_COMPUTE_BIT:
@@ -1731,6 +1818,32 @@
return skip;
}
+bool CoreChecks::ValidateShaderStageGroupNonUniform(SHADER_MODULE_STATE const *module, VkShaderStageFlagBits stage,
+ std::unordered_set<uint32_t> const &accessible_ids) {
+ bool skip = false;
+
+ auto const subgroup_props = phys_dev_ext_props.subgroup_props;
+
+ for (uint32_t id : accessible_ids) {
+ auto inst = module->get_def(id);
+
+ // Check the quad operations.
+ switch (inst.opcode()) {
+ default:
+ break;
+ case spv::OpGroupNonUniformQuadBroadcast:
+ case spv::OpGroupNonUniformQuadSwap:
+ if ((stage != VK_SHADER_STAGE_FRAGMENT_BIT) && (stage != VK_SHADER_STAGE_COMPUTE_BIT)) {
+ skip |= RequireFeature(report_data, subgroup_props.quadOperationsInAllStages,
+ "VkPhysicalDeviceSubgroupProperties::quadOperationsInAllStages");
+ }
+ break;
+ }
+ }
+
+ return skip;
+}
+
bool CoreChecks::ValidateShaderStageInputOutputLimits(SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
PIPELINE_STATE *pipeline, spirv_inst_iter entrypoint) {
if (pStage->stage == VK_SHADER_STAGE_COMPUTE_BIT || pStage->stage == VK_SHADER_STAGE_ALL_GRAPHICS ||
@@ -2564,8 +2677,10 @@
auto descriptor_uses = CollectInterfaceByDescriptorSlot(report_data, module, accessible_ids, &has_writable_descriptor);
// Validate shader capabilities against enabled device features
- skip |= ValidateShaderCapabilities(module, pStage->stage, has_writable_descriptor);
+ skip |= ValidateShaderCapabilities(module, pStage->stage);
+ skip |= ValidateShaderStageWritableDescriptor(pStage->stage, has_writable_descriptor);
skip |= ValidateShaderStageInputOutputLimits(module, pStage, pipeline, entrypoint);
+ skip |= ValidateShaderStageGroupNonUniform(module, pStage->stage, accessible_ids);
skip |= ValidateExecutionModes(module, entrypoint);
skip |= ValidateSpecializationOffsets(report_data, pStage);
skip |= ValidatePushConstantUsage(report_data, pipeline->pipeline_layout.push_constant_ranges.get(), module, accessible_ids,