diff --git a/Android.mk b/Android.mk index ae83c261d..d7fc39290 100644 --- a/Android.mk +++ b/Android.mk @@ -75,7 +75,7 @@ LOCAL_SRC_FILES:= \ 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 ab0ddfbda..a1c05ea39 100644 --- a/src/vulkan/device.cc +++ b/src/vulkan/device.cc @@ -403,121 +403,145 @@ Result Device::Initialize( 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(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(ptr); + switch (s->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR: var_ptrs = static_cast(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(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(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(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(ptr); - } - ptr = s->pNext; + break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: + vulkan11_ptrs = static_cast(ptr); + break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: + vulkan12_ptrs = static_cast(ptr); + break; + default: + break; } + ptr = s->pNext; + } - std::vector 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; - } + // 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"); + } - if ((feature == kVariablePointers || - feature == kVariablePointersStorageBuffer) && - var_ptrs == nullptr) { - return amber::Result( - "Variable pointers requested but feature not returned"); - } + // Next check the fields of the feature structures. + // If Vulkan 1.1 structure exists the features are set there. + if (vulkan11_ptrs) { if (feature == kVariablePointers && - var_ptrs->variablePointers != VK_TRUE) { + vulkan11_ptrs->variablePointers != VK_TRUE) { return amber::Result("Missing variable pointers feature"); } if (feature == kVariablePointersStorageBuffer && - var_ptrs->variablePointersStorageBuffer != VK_TRUE) { + vulkan11_ptrs->variablePointersStorageBuffer != VK_TRUE) { 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 == k16BitStorage_Storage && + vulkan11_ptrs->storageBuffer16BitAccess != VK_TRUE) { + return amber::Result("Missing 16-bit storage access"); } - - 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 == k16BitStorage_UniformAndStorage && + vulkan11_ptrs->uniformAndStorageBuffer16BitAccess != VK_TRUE) { + return amber::Result("Missing 16-bit uniform and storage access"); } - - if (feature == k8BitStorage_Storage && - storage8_ptrs->storageBuffer8BitAccess != VK_TRUE) { - return amber::Result("Missing 8-bit storage access"); + if (feature == k16BitStorage_PushConstant && + vulkan11_ptrs->storagePushConstant16 != VK_TRUE) { + return amber::Result("Missing 16-bit push constant access"); } - if (feature == k8BitStorage_UniformAndStorage && - storage8_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) { - return amber::Result("Missing 8-bit uniform and storage access"); + if (feature == k16BitStorage_InputOutput && + vulkan11_ptrs->storageInputOutput16 != VK_TRUE) { + return amber::Result("Missing 16-bit input/output access"); } - if (feature == k8BitStorage_PushConstant && - storage8_ptrs->storagePushConstant8 != VK_TRUE) { - return amber::Result("Missing 8-bit push constant 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"); } - - if ((feature == k16BitStorage_Storage || - feature == k16BitStorage_UniformAndStorage || - feature == k16BitStorage_PushConstant || - feature == k16BitStorage_InputOutput) && - storage16_ptrs == nullptr) { + if (feature == kVariablePointersStorageBuffer && + var_ptrs->variablePointersStorageBuffer != VK_TRUE) { return amber::Result( - "Shader 16-bit storage requested but feature not returned"); + "Missing variable pointers storage buffer feature"); } - if (feature == k16BitStorage_Storage && storage16_ptrs->storageBuffer16BitAccess != VK_TRUE) { return amber::Result("Missing 16-bit storage access"); @@ -534,31 +558,62 @@ Result Device::Initialize( 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 == kFloat16Int8_Int8 && + vulkan12_ptrs->shaderInt8 != VK_TRUE) { + return amber::Result("Missing int8 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 == kSubgroupSizeControl && - subgroup_size_control_features->subgroupSizeControl != VK_TRUE) { - return amber::Result("Missing subgroup size control 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 == kComputeFullSubgroups && - subgroup_size_control_features->computeFullSubgroups != VK_TRUE) { - return amber::Result("Missing compute full subgroups feature"); + 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 @@ Result Device::Initialize( 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( getInstanceProcAddr(instance_,