Add support for Vulkan 1.2 feature structs (#880)
diff --git a/Android.mk b/Android.mk
index ae83c26..d7fc392 100644
--- a/Android.mk
+++ b/Android.mk
@@ -75,7 +75,7 @@
src/vulkan/vertex_buffer.cc \
src/vulkan_engine_config.cc
LOCAL_STATIC_LIBRARIES:=glslang SPIRV-Tools shaderc
-LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include
+LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include $(LOCAL_PATH)/third_party/vulkan-headers/include
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)
diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc
index ab0ddfb..a1c05ea 100644
--- a/src/vulkan/device.cc
+++ b/src/vulkan/device.cc
@@ -403,66 +403,136 @@
if (!r.IsSuccess())
return r;
- bool use_physical_device_features_2 = false;
- for (auto& ext : required_instance_extensions) {
- if (ext == "VK_KHR_get_physical_device_properties2")
- use_physical_device_features_2 = true;
+ // Check for the core features. We don't know if available_features or
+ // available_features2 is provided, so check both.
+ if (!AreAllRequiredFeaturesSupported(available_features, required_features) &&
+ !AreAllRequiredFeaturesSupported(available_features2.features,
+ required_features)) {
+ return Result(
+ "Vulkan: Device::Initialize given physical device does not support "
+ "required features");
}
- VkPhysicalDeviceFeatures available_vulkan_features =
- VkPhysicalDeviceFeatures();
- if (use_physical_device_features_2) {
- available_vulkan_features = available_features2.features;
-
- VkPhysicalDeviceVariablePointerFeaturesKHR* var_ptrs = nullptr;
- VkPhysicalDeviceFloat16Int8FeaturesKHR* float16_ptrs = nullptr;
- VkPhysicalDevice8BitStorageFeaturesKHR* storage8_ptrs = nullptr;
- VkPhysicalDevice16BitStorageFeaturesKHR* storage16_ptrs = nullptr;
- VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*
- subgroup_size_control_features = nullptr;
- void* ptr = available_features2.pNext;
- while (ptr != nullptr) {
- BaseOutStructure* s = static_cast<BaseOutStructure*>(ptr);
- if (s->sType ==
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR) {
+ // Search for additional features in case they are found in pNext field of
+ // available_features2.
+ VkPhysicalDeviceVariablePointerFeaturesKHR* var_ptrs = nullptr;
+ VkPhysicalDeviceFloat16Int8FeaturesKHR* float16_ptrs = nullptr;
+ VkPhysicalDevice8BitStorageFeaturesKHR* storage8_ptrs = nullptr;
+ VkPhysicalDevice16BitStorageFeaturesKHR* storage16_ptrs = nullptr;
+ VkPhysicalDeviceVulkan11Features* vulkan11_ptrs = nullptr;
+ VkPhysicalDeviceVulkan12Features* vulkan12_ptrs = nullptr;
+ VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*
+ subgroup_size_control_features = nullptr;
+ void* ptr = available_features2.pNext;
+ while (ptr != nullptr) {
+ BaseOutStructure* s = static_cast<BaseOutStructure*>(ptr);
+ switch (s->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR:
var_ptrs =
static_cast<VkPhysicalDeviceVariablePointerFeaturesKHR*>(ptr);
- } else if (s->sType ==
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR) {
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR:
float16_ptrs =
static_cast<VkPhysicalDeviceFloat16Int8FeaturesKHR*>(ptr);
- } else if (s->sType ==
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR) {
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR:
storage8_ptrs =
static_cast<VkPhysicalDevice8BitStorageFeaturesKHR*>(ptr);
- } else if (s->sType ==
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR) {
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR:
storage16_ptrs =
static_cast<VkPhysicalDevice16BitStorageFeaturesKHR*>(ptr);
- } else if (
- s->sType ==
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT) { // NOLINT(whitespace/line_length)
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT:
subgroup_size_control_features =
static_cast<VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*>(ptr);
- }
- ptr = s->pNext;
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES:
+ vulkan11_ptrs = static_cast<VkPhysicalDeviceVulkan11Features*>(ptr);
+ break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES:
+ vulkan12_ptrs = static_cast<VkPhysicalDeviceVulkan12Features*>(ptr);
+ break;
+ default:
+ break;
+ }
+ ptr = s->pNext;
+ }
+
+ // Compare the available additional (non-core) features against the
+ // requirements.
+ //
+ // Vulkan 1.2 added support for defining non-core physical device features
+ // using VkPhysicalDeviceVulkan11Features and VkPhysicalDeviceVulkan12Features
+ // structures. If |vulkan11_ptrs| and/or |vulkan12_ptrs| are null, we must
+ // check for features using the old approach (by checking across various
+ // feature structs); otherwise, we can check features via the new structs.
+ for (const auto& feature : required_features) {
+ // First check the feature structures are provided for the required
+ // features.
+ if ((feature == kVariablePointers ||
+ feature == kVariablePointersStorageBuffer) &&
+ var_ptrs == nullptr && vulkan11_ptrs == nullptr) {
+ return amber::Result(
+ "Variable pointers requested but feature not returned");
+ }
+ if ((feature == k16BitStorage_Storage ||
+ feature == k16BitStorage_UniformAndStorage ||
+ feature == k16BitStorage_PushConstant ||
+ feature == k16BitStorage_InputOutput) &&
+ storage16_ptrs == nullptr && vulkan11_ptrs == nullptr) {
+ return amber::Result(
+ "Shader 16-bit storage requested but feature not returned");
+ }
+ if ((feature == kFloat16Int8_Float16 || feature == kFloat16Int8_Int8) &&
+ float16_ptrs == nullptr && vulkan12_ptrs == nullptr) {
+ return amber::Result(
+ "Shader float16/int8 requested but feature not returned");
+ }
+ if ((feature == k8BitStorage_UniformAndStorage ||
+ feature == k8BitStorage_Storage ||
+ feature == k8BitStorage_PushConstant) &&
+ storage8_ptrs == nullptr && vulkan12_ptrs == nullptr) {
+ return amber::Result(
+ "Shader 8-bit storage requested but feature not returned");
+ }
+ if ((feature == kSubgroupSizeControl || feature == kComputeFullSubgroups) &&
+ subgroup_size_control_features == nullptr) {
+ return amber::Result("Missing subgroup size control features");
}
- std::vector<std::string> required_features1;
- for (const auto& feature : required_features) {
- // No dot means this is a features1 feature.
- if (feature.find_first_of('.') == std::string::npos) {
- required_features1.push_back(feature);
- continue;
- }
+ // Next check the fields of the feature structures.
- if ((feature == kVariablePointers ||
- feature == kVariablePointersStorageBuffer) &&
- var_ptrs == nullptr) {
+ // If Vulkan 1.1 structure exists the features are set there.
+ if (vulkan11_ptrs) {
+ if (feature == kVariablePointers &&
+ vulkan11_ptrs->variablePointers != VK_TRUE) {
+ return amber::Result("Missing variable pointers feature");
+ }
+ if (feature == kVariablePointersStorageBuffer &&
+ vulkan11_ptrs->variablePointersStorageBuffer != VK_TRUE) {
return amber::Result(
- "Variable pointers requested but feature not returned");
+ "Missing variable pointers storage buffer feature");
}
-
+ if (feature == k16BitStorage_Storage &&
+ vulkan11_ptrs->storageBuffer16BitAccess != VK_TRUE) {
+ return amber::Result("Missing 16-bit storage access");
+ }
+ if (feature == k16BitStorage_UniformAndStorage &&
+ vulkan11_ptrs->uniformAndStorageBuffer16BitAccess != VK_TRUE) {
+ return amber::Result("Missing 16-bit uniform and storage access");
+ }
+ if (feature == k16BitStorage_PushConstant &&
+ vulkan11_ptrs->storagePushConstant16 != VK_TRUE) {
+ return amber::Result("Missing 16-bit push constant access");
+ }
+ if (feature == k16BitStorage_InputOutput &&
+ vulkan11_ptrs->storageInputOutput16 != VK_TRUE) {
+ return amber::Result("Missing 16-bit input/output access");
+ }
+ } else {
+ // Vulkan 1.1 structure was not found. Use separate structures per each
+ // feature.
if (feature == kVariablePointers &&
var_ptrs->variablePointers != VK_TRUE) {
return amber::Result("Missing variable pointers feature");
@@ -472,52 +542,6 @@
return amber::Result(
"Missing variable pointers storage buffer feature");
}
-
- if ((feature == kFloat16Int8_Float16 || feature == kFloat16Int8_Int8) &&
- float16_ptrs == nullptr) {
- return amber::Result(
- "Shader float16/int8 requested but feature not returned");
- }
-
- if (feature == kFloat16Int8_Float16 &&
- float16_ptrs->shaderFloat16 != VK_TRUE) {
- return amber::Result("Missing float16 feature");
- }
-
- if (feature == kFloat16Int8_Int8 && float16_ptrs->shaderInt8 != VK_TRUE) {
- return amber::Result("Missing int8 feature");
- }
-
- if ((feature == k8BitStorage_UniformAndStorage ||
- feature == k8BitStorage_Storage ||
- feature == k8BitStorage_PushConstant) &&
- storage8_ptrs == nullptr) {
- return amber::Result(
- "Shader 8-bit storage requested but feature not returned");
- }
-
- if (feature == k8BitStorage_Storage &&
- storage8_ptrs->storageBuffer8BitAccess != VK_TRUE) {
- return amber::Result("Missing 8-bit storage access");
- }
- if (feature == k8BitStorage_UniformAndStorage &&
- storage8_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
- return amber::Result("Missing 8-bit uniform and storage access");
- }
- if (feature == k8BitStorage_PushConstant &&
- storage8_ptrs->storagePushConstant8 != VK_TRUE) {
- return amber::Result("Missing 8-bit push constant access");
- }
-
- if ((feature == k16BitStorage_Storage ||
- feature == k16BitStorage_UniformAndStorage ||
- feature == k16BitStorage_PushConstant ||
- feature == k16BitStorage_InputOutput) &&
- storage16_ptrs == nullptr) {
- return amber::Result(
- "Shader 16-bit storage requested but feature not returned");
- }
-
if (feature == k16BitStorage_Storage &&
storage16_ptrs->storageBuffer16BitAccess != VK_TRUE) {
return amber::Result("Missing 16-bit storage access");
@@ -534,31 +558,62 @@
storage16_ptrs->storageInputOutput16 != VK_TRUE) {
return amber::Result("Missing 16-bit input/output access");
}
+ }
- if ((feature == kSubgroupSizeControl ||
- feature == kComputeFullSubgroups) &&
- subgroup_size_control_features == nullptr) {
- return amber::Result("Missing subgroup size control features");
+ // If Vulkan 1.2 structure exists the features are set there.
+ if (vulkan12_ptrs) {
+ if (feature == kFloat16Int8_Float16 &&
+ vulkan12_ptrs->shaderFloat16 != VK_TRUE) {
+ return amber::Result("Missing float16 feature");
}
- if (feature == kSubgroupSizeControl &&
- subgroup_size_control_features->subgroupSizeControl != VK_TRUE) {
- return amber::Result("Missing subgroup size control feature");
+ if (feature == kFloat16Int8_Int8 &&
+ vulkan12_ptrs->shaderInt8 != VK_TRUE) {
+ return amber::Result("Missing int8 feature");
}
- if (feature == kComputeFullSubgroups &&
- subgroup_size_control_features->computeFullSubgroups != VK_TRUE) {
- return amber::Result("Missing compute full subgroups feature");
+ if (feature == k8BitStorage_Storage &&
+ vulkan12_ptrs->storageBuffer8BitAccess != VK_TRUE) {
+ return amber::Result("Missing 8-bit storage access");
+ }
+ if (feature == k8BitStorage_UniformAndStorage &&
+ vulkan12_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
+ return amber::Result("Missing 8-bit uniform and storage access");
+ }
+ if (feature == k8BitStorage_PushConstant &&
+ vulkan12_ptrs->storagePushConstant8 != VK_TRUE) {
+ return amber::Result("Missing 8-bit push constant access");
+ }
+ } else {
+ // Vulkan 1.2 structure was not found. Use separate structures per each
+ // feature.
+ if (feature == kFloat16Int8_Float16 &&
+ float16_ptrs->shaderFloat16 != VK_TRUE) {
+ return amber::Result("Missing float16 feature");
+ }
+ if (feature == kFloat16Int8_Int8 && float16_ptrs->shaderInt8 != VK_TRUE) {
+ return amber::Result("Missing int8 feature");
+ }
+ if (feature == k8BitStorage_Storage &&
+ storage8_ptrs->storageBuffer8BitAccess != VK_TRUE) {
+ return amber::Result("Missing 8-bit storage access");
+ }
+ if (feature == k8BitStorage_UniformAndStorage &&
+ storage8_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
+ return amber::Result("Missing 8-bit uniform and storage access");
+ }
+ if (feature == k8BitStorage_PushConstant &&
+ storage8_ptrs->storagePushConstant8 != VK_TRUE) {
+ return amber::Result("Missing 8-bit push constant access");
}
}
- } else {
- available_vulkan_features = available_features;
- }
-
- if (!AreAllRequiredFeaturesSupported(available_vulkan_features,
- required_features)) {
- return Result(
- "Vulkan: Device::Initialize given physical device does not support "
- "required features");
+ if (feature == kSubgroupSizeControl &&
+ subgroup_size_control_features->subgroupSizeControl != VK_TRUE) {
+ return amber::Result("Missing subgroup size control feature");
+ }
+ if (feature == kComputeFullSubgroups &&
+ subgroup_size_control_features->computeFullSubgroups != VK_TRUE) {
+ return amber::Result("Missing compute full subgroups feature");
+ }
}
if (!AreAllExtensionsSupported(available_extensions,
@@ -574,11 +629,24 @@
ptrs_.vkGetPhysicalDeviceMemoryProperties(physical_device_,
&physical_memory_properties_);
+ bool use_physical_device_features_2 = false;
+ for (auto& ext : required_instance_extensions) {
+ if (ext == "VK_KHR_get_physical_device_properties2")
+ use_physical_device_features_2 = true;
+ }
+
subgroup_size_control_properties_ = {};
const bool needs_subgroup_size_control =
std::find(required_features.begin(), required_features.end(),
kSubgroupSizeControl) != required_features.end();
- if (needs_subgroup_size_control && use_physical_device_features_2) {
+
+ if (needs_subgroup_size_control) {
+ if (!use_physical_device_features_2) {
+ return Result(
+ "Vulkan: Device::Initialize subgroup size control feature also "
+ "requires VK_KHR_get_physical_device_properties2");
+ }
+
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
getInstanceProcAddr(instance_,