VK_EXT_subgroup_size_control support
This CL is a minimal implementation of VK_EXT_subgroup_size_control.
According to the spec:
"Previously Vulkan exposed a single subgroup size per physical
device, with the expectation that implementations will behave
as if all subgroups have the same size"
By setting:
- VkPhysicalDeviceSubgroupSizeControlPropertiesEXT::minSubgroupSize
- VkPhysicalDeviceSubgroupSizeControlPropertiesEXT::maxSubgroupSize
the same value as:
- VkPhysicalDeviceSubgroupProperties::subgroupSize
we can support the feature without any other modifications.
maxComputeWorkgroupSubgroups is set to
MAX_COMPUTE_WORKGROUP_INVOCATIONS / minSubgroupSize
which is currently 256 / 4 = 64
Tests: dEQP-VK.subgroups.*_contro*
Bug: b/204502920
Change-Id: I3995a530465067871992ebc8ed3b0e7250386317
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/58828
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Commit-Queue: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkConfig.hpp b/src/Vulkan/VkConfig.hpp
index a6145bd..1240513 100644
--- a/src/Vulkan/VkConfig.hpp
+++ b/src/Vulkan/VkConfig.hpp
@@ -66,6 +66,8 @@
MAX_DESCRIPTOR_SET_UNIFORM_BUFFERS_DYNAMIC +
MAX_DESCRIPTOR_SET_STORAGE_BUFFERS_DYNAMIC;
+constexpr uint32_t MAX_COMPUTE_WORKGROUP_INVOCATIONS = 256;
+
constexpr float MAX_POINT_SIZE = 1023.0;
constexpr int MAX_SAMPLER_ALLOCATION_COUNT = 4000;
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 40f1c44..0d1dc1d 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -343,6 +343,12 @@
features->advancedBlendCoherentOperations = VK_FALSE;
}
+static void getPhysicalDeviceSubgroupSizeControlFeatures(VkPhysicalDeviceSubgroupSizeControlFeatures *features)
+{
+ features->subgroupSizeControl = VK_TRUE;
+ features->computeFullSubgroups = VK_TRUE;
+}
+
static void getPhysicalDevice4444FormatsFeaturesExt(VkPhysicalDevice4444FormatsFeaturesEXT *features)
{
features->formatA4R4G4B4 = VK_TRUE;
@@ -451,6 +457,9 @@
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT:
getPhysicalDeviceBlendOperationAdvancedFeaturesExt(reinterpret_cast<VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *>(curExtension));
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES:
+ getPhysicalDeviceSubgroupSizeControlFeatures(reinterpret_cast<VkPhysicalDeviceSubgroupSizeControlFeatures *>(curExtension));
+ break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT:
getPhysicalDevice4444FormatsFeaturesExt(reinterpret_cast<struct VkPhysicalDevice4444FormatsFeaturesEXT *>(curExtension));
break;
@@ -537,7 +546,7 @@
28, // maxFragmentCombinedOutputResources
32768, // maxComputeSharedMemorySize
{ 65535, 65535, 65535 }, // maxComputeWorkGroupCount[3]
- 256, // maxComputeWorkGroupInvocations
+ vk::MAX_COMPUTE_WORKGROUP_INVOCATIONS, // maxComputeWorkGroupInvocations
{ 256, 256, 64 }, // maxComputeWorkGroupSize[3]
vk::SUBPIXEL_PRECISION_BITS, // subPixelPrecisionBits
4, // subTexelPrecisionBits
@@ -1062,6 +1071,17 @@
properties->advancedBlendAllOperations = VK_FALSE;
}
+void PhysicalDevice::getProperties(VkPhysicalDeviceSubgroupSizeControlProperties *properties) const
+{
+ VkPhysicalDeviceSubgroupProperties subgroupProperties = {};
+ getProperties(&subgroupProperties);
+ properties->minSubgroupSize = subgroupProperties.subgroupSize;
+ properties->maxSubgroupSize = subgroupProperties.subgroupSize;
+ properties->maxComputeWorkgroupSubgroups = vk::MAX_COMPUTE_WORKGROUP_INVOCATIONS /
+ properties->minSubgroupSize;
+ properties->requiredSubgroupSizeStages = subgroupProperties.supportedStages;
+}
+
template<typename T>
static void getSamplerFilterMinmaxProperties(T *properties)
{
@@ -1235,6 +1255,15 @@
return CheckFeature(requested, supported, advancedBlendCoherentOperations);
}
+
+bool PhysicalDevice::hasExtendedFeatures(const VkPhysicalDeviceSubgroupSizeControlFeatures *requested) const
+{
+ auto supported = getSupportedFeatures(requested);
+
+ return CheckFeature(requested, supported, subgroupSizeControl) &&
+ CheckFeature(requested, supported, computeFullSubgroups);
+}
+
#undef CheckFeature
void PhysicalDevice::GetFormatProperties(Format format, VkFormatProperties *pFormatProperties)
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
index 0e3cca9..2bef6bd 100644
--- a/src/Vulkan/VkPhysicalDevice.hpp
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -44,6 +44,7 @@
bool hasExtendedFeatures(const VkPhysicalDeviceVulkan12Features *features) const;
bool hasExtendedFeatures(const VkPhysicalDeviceDepthClipEnableFeaturesEXT *features) const;
bool hasExtendedFeatures(const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *features) const;
+ bool hasExtendedFeatures(const VkPhysicalDeviceSubgroupSizeControlFeatures *requested) const;
const VkPhysicalDeviceProperties &getProperties() const;
void getProperties(VkPhysicalDeviceIDProperties *properties) const;
@@ -74,6 +75,7 @@
void getProperties(VkPhysicalDeviceDepthStencilResolveProperties *properties) const;
void getProperties(VkPhysicalDeviceCustomBorderColorPropertiesEXT *properties) const;
void getProperties(VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *properties) const;
+ void getProperties(VkPhysicalDeviceSubgroupSizeControlProperties *properties) const;
void getProperties(VkPhysicalDeviceVulkan11Properties *properties) const;
static void GetFormatProperties(Format format, VkFormatProperties *pFormatProperties);
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 0049524..56d0cbd 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -331,9 +331,10 @@
pipelineCreationFeedback.stageCreationBegins(stageIndex);
- if(stageInfo.flags != 0)
+ if((stageInfo.flags &
+ ~(VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT |
+ VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT)) != 0)
{
- // Vulkan 1.2: "flags must be 0"
UNSUPPORTED("pStage->flags %d", int(stageInfo.flags));
}
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 4ee3585..2892e97 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -418,6 +418,7 @@
// Vulkan 1.3 promoted extensions
{ { VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME, VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION } },
{ { VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME, VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION } },
+ { { VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION } },
{ { VK_EXT_TOOLING_INFO_EXTENSION_NAME, VK_EXT_TOOLING_INFO_SPEC_VERSION } },
{ { VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME, VK_KHR_COPY_COMMANDS_2_SPEC_VERSION } },
{ { VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME, VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION } },
@@ -933,6 +934,16 @@
}
}
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES:
+ {
+ const auto *subgroupSizeControlFeatures = reinterpret_cast<const VkPhysicalDeviceSubgroupSizeControlFeatures *>(extensionCreateInfo);
+ bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(subgroupSizeControlFeatures);
+ if(!hasFeatures)
+ {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+ }
+ break;
// These structs are supported, but no behavior changes based on their feature bools
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES:
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES:
@@ -3380,6 +3391,12 @@
vk::Cast(physicalDevice)->getProperties(properties);
}
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES:
+ {
+ auto properties = reinterpret_cast<VkPhysicalDeviceSubgroupSizeControlProperties *>(extensionProperties);
+ vk::Cast(physicalDevice)->getProperties(properties);
+ }
+ break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR:
break;
default: