- Restored removed functions

- Restored pNext chain to device (appends to the end of the ExtentionFeatures chain)
- Style changes
- Migrated ExtensionFeatures into detail
This commit is contained in:
vibi-manx 2021-04-14 17:41:33 -05:00 committed by Charles Giessen
parent 21e400cfcc
commit 0359ceb3fb
3 changed files with 160 additions and 106 deletions

View File

@ -846,8 +846,8 @@ std::vector<const char*> check_device_extension_support(
// clang-format off // clang-format off
bool supports_features(VkPhysicalDeviceFeatures supported, bool supports_features(VkPhysicalDeviceFeatures supported,
VkPhysicalDeviceFeatures requested, VkPhysicalDeviceFeatures requested,
const std::vector<ExtensionFeatures>& extension_supported, std::vector<ExtensionFeatures> const& extension_supported,
const std::vector<ExtensionFeatures>& extension_requested) { std::vector<ExtensionFeatures> const& extension_requested) {
if (requested.robustBufferAccess && !supported.robustBufferAccess) return false; if (requested.robustBufferAccess && !supported.robustBufferAccess) return false;
if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false; if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false;
if (requested.imageCubeArray && !supported.imageCubeArray) return false; if (requested.imageCubeArray && !supported.imageCubeArray) return false;
@ -992,7 +992,7 @@ uint32_t get_present_queue_index(VkPhysicalDevice const phys_device,
PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details( PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details(
uint32_t instance_version, VkPhysicalDevice phys_device, uint32_t instance_version, VkPhysicalDevice phys_device,
std::vector<ExtensionFeatures> extension_features_as_template) const { std::vector<detail::ExtensionFeatures> extension_features_as_template) const {
PhysicalDeviceSelector::PhysicalDeviceDesc desc{}; PhysicalDeviceSelector::PhysicalDeviceDesc desc{};
desc.phys_device = phys_device; desc.phys_device = phys_device;
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties>( auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties>(
@ -1007,7 +1007,7 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi
desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
desc.extension_features = extension_features_as_template; desc.extension_features = extension_features_as_template;
if (instance_version >= VK_API_VERSION_1_1) { if (instance_version >= VK_API_VERSION_1_1) {
ExtensionFeatures* prev = nullptr; detail::ExtensionFeatures* prev = nullptr;
for(auto& extension : desc.extension_features) { for(auto& extension : desc.extension_features) {
if(prev != nullptr) { if(prev != nullptr) {
prev->structure->pNext = extension.structure; prev->structure->pNext = extension.structure;
@ -1260,12 +1260,12 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::set_desired_version(uint32_t maj
// Just calls add_required_features // Just calls add_required_features
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11( PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11(
VkPhysicalDeviceVulkan11Features const& features_11) { VkPhysicalDeviceVulkan11Features const& features_11) {
add_required_features(features_11); add_required_extension_features(features_11);
return *this; return *this;
} }
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12( PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12(
VkPhysicalDeviceVulkan12Features const& features_12) { VkPhysicalDeviceVulkan12Features const& features_12) {
add_required_features(features_12); add_required_extension_features(features_12);
return *this; return *this;
} }
#endif #endif
@ -1401,21 +1401,24 @@ detail::Result<Device> DeviceBuilder::build() const {
bool has_phys_dev_features_2 = false; bool has_phys_dev_features_2 = false;
// Setup the pNexts of all the extension features
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
// Setup the pNexts of all the extension features
std::vector<detail::ExtensionFeatures> match = physical_device.extension_features;
VkPhysicalDeviceFeatures2 local_features2{}; VkPhysicalDeviceFeatures2 local_features2{};
VkBaseOutStructure* tail = nullptr;
if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0) && if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0) &&
physical_device.extension_features.size() > 0) { match.size() > 0) {
ExtensionFeatures* prev = nullptr; detail::ExtensionFeatures* prev = nullptr;
for(auto& extension : physical_device.extension_features) { for(auto& extension : match) {
if(prev != nullptr) { if(prev != nullptr) {
prev->structure->pNext = extension.structure; prev->structure->pNext = extension.structure;
} }
prev = &extension; prev = &extension;
tail = prev->structure;
} }
local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
local_features2.features = physical_device.features; local_features2.features = physical_device.features;
local_features2.pNext = physical_device.extension_features[0].structure; local_features2.pNext = match.front().structure;
has_phys_dev_features_2 = true; has_phys_dev_features_2 = true;
} }
#endif #endif
@ -1427,19 +1430,31 @@ detail::Result<Device> DeviceBuilder::build() const {
device_create_info.pQueueCreateInfos = queueCreateInfos.data(); device_create_info.pQueueCreateInfos = queueCreateInfos.data();
device_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size()); device_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
device_create_info.ppEnabledExtensionNames = extensions.data(); device_create_info.ppEnabledExtensionNames = extensions.data();
detail::setup_pNext_chain(device_create_info, info.pNext_chain);
#if defined(VK_API_VERSION_1_1)
// VUID-VkDeviceCreateInfo-pNext-00373 - don't add pEnabledFeatures if the phys_dev_features_2 is present // VUID-VkDeviceCreateInfo-pNext-00373 - don't add pEnabledFeatures if the phys_dev_features_2 is present
if (!has_phys_dev_features_2) { if (has_phys_dev_features_2) {
device_create_info.pEnabledFeatures = &physical_device.features;
} else {
device_create_info.pNext = &local_features2; device_create_info.pNext = &local_features2;
if(info.pNext_chain.size() > 0) {
match.back().structure->pNext = info.pNext_chain.front();
} }
} else {
device_create_info.pEnabledFeatures = &physical_device.features;
}
#else
device_create_info.pEnabledFeatures = &physical_device.features;
#endif
Device device; Device device;
VkResult res = detail::vulkan_functions().fp_vkCreateDevice( VkResult res = detail::vulkan_functions().fp_vkCreateDevice(
physical_device.physical_device, &device_create_info, info.allocation_callbacks, &device.device); physical_device.physical_device, &device_create_info, info.allocation_callbacks, &device.device);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return { DeviceError::failed_create_device, res }; return { DeviceError::failed_create_device, res };
} }
device.physical_device = physical_device; device.physical_device = physical_device;
device.surface = physical_device.surface; device.surface = physical_device.surface;
device.queue_families = physical_device.queue_families; device.queue_families = physical_device.queue_families;

View File

@ -115,86 +115,6 @@ template <typename T> class Result {
bool m_init; bool m_init;
}; };
} // namespace detail
enum class InstanceError {
vulkan_unavailable,
vulkan_version_unavailable,
vulkan_version_1_1_unavailable,
vulkan_version_1_2_unavailable,
failed_create_instance,
failed_create_debug_messenger,
requested_layers_not_present,
requested_extensions_not_present,
windowing_extensions_not_present,
};
enum class PhysicalDeviceError {
no_surface_provided,
failed_enumerate_physical_devices,
no_physical_devices_found,
no_suitable_device,
};
enum class QueueError {
present_unavailable,
graphics_unavailable,
compute_unavailable,
transfer_unavailable,
queue_index_out_of_range,
invalid_queue_family_index
};
enum class DeviceError {
failed_create_device,
};
enum class SwapchainError {
surface_handle_not_provided,
failed_query_surface_support_details,
failed_create_swapchain,
failed_get_swapchain_images,
failed_create_swapchain_image_views,
};
std::error_code make_error_code(InstanceError instance_error);
std::error_code make_error_code(PhysicalDeviceError physical_device_error);
std::error_code make_error_code(QueueError queue_error);
std::error_code make_error_code(DeviceError device_error);
std::error_code make_error_code(SwapchainError swapchain_error);
const char* to_string_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT s);
const char* to_string_message_type(VkDebugUtilsMessageTypeFlagsEXT s);
const char* to_string(InstanceError err);
const char* to_string(PhysicalDeviceError err);
const char* to_string(QueueError err);
const char* to_string(DeviceError err);
const char* to_string(SwapchainError err);
// Gathers useful information about the available vulkan capabilities, like layers and instance
// extensions. Use this for enabling features conditionally, ie if you would like an extension but
// can use a fallback if it isn't supported but need to know if support is available first.
struct SystemInfo {
private:
SystemInfo();
public:
// Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail.
static detail::Result<SystemInfo> get_system_info();
static detail::Result<SystemInfo> get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
// Returns true if a layer is available
bool is_layer_available(const char* layer_name) const;
// Returns true if an extension is available
bool is_extension_available(const char* extension_name) const;
std::vector<VkLayerProperties> available_layers;
std::vector<VkExtensionProperties> available_extensions;
bool validation_layers_available = false;
bool debug_utils_available = false;
};
class InstanceBuilder;
class PhysicalDeviceSelector;
struct ExtensionFeatures { struct ExtensionFeatures {
using DeleteProc = void(*)(ExtensionFeatures&); using DeleteProc = void(*)(ExtensionFeatures&);
@ -313,6 +233,86 @@ struct ExtensionFeatures {
CopyProc copy_proc = nullptr; CopyProc copy_proc = nullptr;
}; };
} // namespace detail
enum class InstanceError {
vulkan_unavailable,
vulkan_version_unavailable,
vulkan_version_1_1_unavailable,
vulkan_version_1_2_unavailable,
failed_create_instance,
failed_create_debug_messenger,
requested_layers_not_present,
requested_extensions_not_present,
windowing_extensions_not_present,
};
enum class PhysicalDeviceError {
no_surface_provided,
failed_enumerate_physical_devices,
no_physical_devices_found,
no_suitable_device,
};
enum class QueueError {
present_unavailable,
graphics_unavailable,
compute_unavailable,
transfer_unavailable,
queue_index_out_of_range,
invalid_queue_family_index
};
enum class DeviceError {
failed_create_device,
};
enum class SwapchainError {
surface_handle_not_provided,
failed_query_surface_support_details,
failed_create_swapchain,
failed_get_swapchain_images,
failed_create_swapchain_image_views,
};
std::error_code make_error_code(InstanceError instance_error);
std::error_code make_error_code(PhysicalDeviceError physical_device_error);
std::error_code make_error_code(QueueError queue_error);
std::error_code make_error_code(DeviceError device_error);
std::error_code make_error_code(SwapchainError swapchain_error);
const char* to_string_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT s);
const char* to_string_message_type(VkDebugUtilsMessageTypeFlagsEXT s);
const char* to_string(InstanceError err);
const char* to_string(PhysicalDeviceError err);
const char* to_string(QueueError err);
const char* to_string(DeviceError err);
const char* to_string(SwapchainError err);
// Gathers useful information about the available vulkan capabilities, like layers and instance
// extensions. Use this for enabling features conditionally, ie if you would like an extension but
// can use a fallback if it isn't supported but need to know if support is available first.
struct SystemInfo {
private:
SystemInfo();
public:
// Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail.
static detail::Result<SystemInfo> get_system_info();
static detail::Result<SystemInfo> get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
// Returns true if a layer is available
bool is_layer_available(const char* layer_name) const;
// Returns true if an extension is available
bool is_extension_available(const char* extension_name) const;
std::vector<VkLayerProperties> available_layers;
std::vector<VkExtensionProperties> available_extensions;
bool validation_layers_available = false;
bool debug_utils_available = false;
};
class InstanceBuilder;
class PhysicalDeviceSelector;
struct Instance { struct Instance {
VkInstance instance = VK_NULL_HANDLE; VkInstance instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
@ -473,7 +473,7 @@ struct PhysicalDevice {
uint32_t instance_version = VK_MAKE_VERSION(1, 0, 0); uint32_t instance_version = VK_MAKE_VERSION(1, 0, 0);
std::vector<const char*> extensions_to_enable; std::vector<const char*> extensions_to_enable;
std::vector<VkQueueFamilyProperties> queue_families; std::vector<VkQueueFamilyProperties> queue_families;
mutable std::vector<ExtensionFeatures> extension_features; std::vector<detail::ExtensionFeatures> extension_features;
bool defer_surface_initialization = false; bool defer_surface_initialization = false;
friend class PhysicalDeviceSelector; friend class PhysicalDeviceSelector;
friend class DeviceBuilder; friend class DeviceBuilder;
@ -535,15 +535,14 @@ class PhysicalDeviceSelector {
PhysicalDeviceSelector& set_minimum_version(uint32_t major, uint32_t minor); PhysicalDeviceSelector& set_minimum_version(uint32_t major, uint32_t minor);
// Require a physical device which supports a specific set of general/extension features. // Require a physical device which supports a specific set of general/extension features.
template <typename T>
PhysicalDeviceSelector& add_required_features(T const& features) {
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
criteria.extension_features.push_back(ExtensionFeatures::make(features)); template <typename T>
#endif PhysicalDeviceSelector& add_required_extension_features(T const& features) {
criteria.extension_features.push_back(detail::ExtensionFeatures::make(features));
return *this; return *this;
} }
template<> #endif
PhysicalDeviceSelector& add_required_features<VkPhysicalDeviceFeatures>(VkPhysicalDeviceFeatures const& features) { PhysicalDeviceSelector& set_required_features(VkPhysicalDeviceFeatures const& features) {
criteria.required_features = features; criteria.required_features = features;
return *this; return *this;
} }
@ -581,7 +580,7 @@ class PhysicalDeviceSelector {
VkPhysicalDeviceMemoryProperties mem_properties{}; VkPhysicalDeviceMemoryProperties mem_properties{};
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 device_features2{}; VkPhysicalDeviceFeatures2 device_features2{};
std::vector<ExtensionFeatures> extension_features; std::vector<detail::ExtensionFeatures> extension_features;
#endif #endif
}; };
@ -590,7 +589,7 @@ class PhysicalDeviceSelector {
PhysicalDeviceDesc populate_device_details(uint32_t instance_version, PhysicalDeviceDesc populate_device_details(uint32_t instance_version,
VkPhysicalDevice phys_device, VkPhysicalDevice phys_device,
std::vector<ExtensionFeatures> extension_features_as_template) const; std::vector<detail::ExtensionFeatures> extension_features_as_template) const;
struct SelectionCriteria { struct SelectionCriteria {
PreferredDeviceType preferred_type = PreferredDeviceType::discrete; PreferredDeviceType preferred_type = PreferredDeviceType::discrete;
@ -612,7 +611,7 @@ class PhysicalDeviceSelector {
VkPhysicalDeviceFeatures required_features{}; VkPhysicalDeviceFeatures required_features{};
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 required_features2{}; VkPhysicalDeviceFeatures2 required_features2{};
std::vector<ExtensionFeatures> extension_features; std::vector<detail::ExtensionFeatures> extension_features;
#endif #endif
bool defer_surface_initialization = false; bool defer_surface_initialization = false;
bool use_first_gpu_unconditionally = false; bool use_first_gpu_unconditionally = false;
@ -670,6 +669,13 @@ class DeviceBuilder {
// If a custom queue setup is provided, getting the queues and queue indexes is up to the application. // If a custom queue setup is provided, getting the queues and queue indexes is up to the application.
DeviceBuilder& custom_queue_setup(std::vector<CustomQueueDescription> queue_descriptions); DeviceBuilder& custom_queue_setup(std::vector<CustomQueueDescription> queue_descriptions);
// Add a structure to the pNext chain of VkDeviceCreateInfo.
// The structure must be valid when DeviceBuilder::build() is called.
template <typename T> DeviceBuilder& add_pNext(T* structure) {
info.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
// Provide custom allocation callbacks. // Provide custom allocation callbacks.
DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks); DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
@ -677,6 +683,7 @@ class DeviceBuilder {
PhysicalDevice physical_device; PhysicalDevice physical_device;
struct DeviceInfo { struct DeviceInfo {
VkDeviceCreateFlags flags = 0; VkDeviceCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
std::vector<CustomQueueDescription> queue_descriptions; std::vector<CustomQueueDescription> queue_descriptions;
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
} info; } info;

View File

@ -411,6 +411,38 @@ TEST_CASE("ReLoading Vulkan Manually", "[VkBootstrap.loading]") {
} }
} }
#if defined(VK_API_VERSION_1_1)
TEST_CASE("Querying Required Extension Features", "[VkBootstrap.version]") {
GIVEN("A working instance") {
vkb::InstanceBuilder builder;
auto instance_ret =
builder.request_validation_layers().require_api_version(1, 2).set_headless().build();
REQUIRE(instance_ret.has_value());
// Requires a device that supports runtime descriptor arrays via descriptor indexing extension.
{
VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_features{};
descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
descriptor_indexing_features.runtimeDescriptorArray = true;
vkb::PhysicalDeviceSelector selector(instance_ret.value());
auto phys_dev_ret =
selector.add_required_extension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME).
add_required_extension_features(descriptor_indexing_features).select();
// Ignore if hardware support isn't true
REQUIRE(phys_dev_ret.has_value());
vkb::DeviceBuilder device_builder(phys_dev_ret.value());
auto device_ret = device_builder.build();
REQUIRE(device_ret.has_value());
vkb::destroy_device(device_ret.value());
}
vkb::destroy_instance(instance_ret.value());
}
}
#endif
#if defined(VK_API_VERSION_1_2) #if defined(VK_API_VERSION_1_2)
TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") { TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") {
GIVEN("A working instance") { GIVEN("A working instance") {