diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index 9a81c8b..86e960f 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -846,8 +846,8 @@ std::vector check_device_extension_support( // clang-format off bool supports_features(VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested, - std::vector const& extension_supported, - std::vector const& extension_requested) { + const std::vector& extension_supported, + const std::vector& extension_requested) { if (requested.robustBufferAccess && !supported.robustBufferAccess) return false; if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) 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( uint32_t instance_version, VkPhysicalDevice phys_device, - std::vector extension_features_as_template) const { + std::vector extension_features_as_template) const { PhysicalDeviceSelector::PhysicalDeviceDesc desc{}; desc.phys_device = phys_device; auto queue_families = detail::get_vector_noerror( @@ -1007,7 +1007,7 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; desc.extension_features = extension_features_as_template; if (instance_version >= VK_API_VERSION_1_1) { - detail::ExtensionFeatures* prev = nullptr; + ExtensionFeatures* prev = nullptr; for(auto& extension : desc.extension_features) { if(prev != nullptr) { prev->structure->pNext = extension.structure; @@ -1260,12 +1260,12 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::set_desired_version(uint32_t maj // Just calls add_required_features PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11( VkPhysicalDeviceVulkan11Features const& features_11) { - add_required_extension_features(features_11); + add_required_features(features_11); return *this; } PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12( VkPhysicalDeviceVulkan12Features const& features_12) { - add_required_extension_features(features_12); + add_required_features(features_12); return *this; } #endif @@ -1401,24 +1401,21 @@ detail::Result DeviceBuilder::build() const { bool has_phys_dev_features_2 = false; +// Setup the pNexts of all the extension features #if defined(VK_API_VERSION_1_1) - // Setup the pNexts of all the extension features - std::vector match = physical_device.extension_features; VkPhysicalDeviceFeatures2 local_features2{}; - VkBaseOutStructure* tail = nullptr; if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0) && - match.size() > 0) { - detail::ExtensionFeatures* prev = nullptr; - for(auto& extension : match) { + physical_device.extension_features.size() > 0) { + ExtensionFeatures* prev = nullptr; + for(auto& extension : physical_device.extension_features) { if(prev != nullptr) { prev->structure->pNext = extension.structure; } prev = &extension; - tail = prev->structure; } local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; local_features2.features = physical_device.features; - local_features2.pNext = match.front().structure; + local_features2.pNext = physical_device.extension_features[0].structure; has_phys_dev_features_2 = true; } #endif @@ -1430,31 +1427,19 @@ detail::Result DeviceBuilder::build() const { device_create_info.pQueueCreateInfos = queueCreateInfos.data(); device_create_info.enabledExtensionCount = static_cast(extensions.size()); 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 - if (has_phys_dev_features_2) { - device_create_info.pNext = &local_features2; - if(info.pNext_chain.size() > 0) { - match.back().structure->pNext = info.pNext_chain.front(); - } + if (!has_phys_dev_features_2) { + device_create_info.pEnabledFeatures = &physical_device.features; } else { - device_create_info.pEnabledFeatures = &physical_device.features; - } -#else - device_create_info.pEnabledFeatures = &physical_device.features; -#endif + device_create_info.pNext = &local_features2; + } Device device; - VkResult res = detail::vulkan_functions().fp_vkCreateDevice( physical_device.physical_device, &device_create_info, info.allocation_callbacks, &device.device); if (res != VK_SUCCESS) { return { DeviceError::failed_create_device, res }; } - device.physical_device = physical_device; device.surface = physical_device.surface; device.queue_families = physical_device.queue_families; diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 8111cf9..e2fb789 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -115,6 +115,86 @@ template class Result { 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 get_system_info(); + static detail::Result 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 available_layers; + std::vector available_extensions; + bool validation_layers_available = false; + bool debug_utils_available = false; +}; + + +class InstanceBuilder; +class PhysicalDeviceSelector; + struct ExtensionFeatures { using DeleteProc = void(*)(ExtensionFeatures&); @@ -233,86 +313,6 @@ struct ExtensionFeatures { 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 get_system_info(); - static detail::Result 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 available_layers; - std::vector available_extensions; - bool validation_layers_available = false; - bool debug_utils_available = false; -}; - - -class InstanceBuilder; -class PhysicalDeviceSelector; - struct Instance { VkInstance instance = 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); std::vector extensions_to_enable; std::vector queue_families; - std::vector extension_features; + mutable std::vector extension_features; bool defer_surface_initialization = false; friend class PhysicalDeviceSelector; friend class DeviceBuilder; @@ -534,15 +534,16 @@ class PhysicalDeviceSelector { // Require a physical device that supports a (major, minor) version of vulkan. PhysicalDeviceSelector& set_minimum_version(uint32_t major, uint32_t minor); - // Require a physical device which supports a specific set of general/extension features. -#if defined(VK_API_VERSION_1_1) +// Require a physical device which supports a specific set of general/extension features. template - PhysicalDeviceSelector& add_required_extension_features(T const& features) { - criteria.extension_features.push_back(detail::ExtensionFeatures::make(features)); + PhysicalDeviceSelector& add_required_features(T const& features) { +#if defined(VK_API_VERSION_1_1) + criteria.extension_features.push_back(ExtensionFeatures::make(features)); +#endif return *this; } -#endif - PhysicalDeviceSelector& set_required_features(VkPhysicalDeviceFeatures const& features) { + template<> + PhysicalDeviceSelector& add_required_features(VkPhysicalDeviceFeatures const& features) { criteria.required_features = features; return *this; } @@ -580,7 +581,7 @@ class PhysicalDeviceSelector { VkPhysicalDeviceMemoryProperties mem_properties{}; #if defined(VK_API_VERSION_1_1) VkPhysicalDeviceFeatures2 device_features2{}; - std::vector extension_features; + std::vector extension_features; #endif }; @@ -589,7 +590,7 @@ class PhysicalDeviceSelector { PhysicalDeviceDesc populate_device_details(uint32_t instance_version, VkPhysicalDevice phys_device, - std::vector extension_features_as_template) const; + std::vector extension_features_as_template) const; struct SelectionCriteria { PreferredDeviceType preferred_type = PreferredDeviceType::discrete; @@ -611,7 +612,7 @@ class PhysicalDeviceSelector { VkPhysicalDeviceFeatures required_features{}; #if defined(VK_API_VERSION_1_1) VkPhysicalDeviceFeatures2 required_features2{}; - std::vector extension_features; + std::vector extension_features; #endif bool defer_surface_initialization = false; bool use_first_gpu_unconditionally = false; @@ -669,13 +670,6 @@ class DeviceBuilder { // If a custom queue setup is provided, getting the queues and queue indexes is up to the application. DeviceBuilder& custom_queue_setup(std::vector queue_descriptions); - // Add a structure to the pNext chain of VkDeviceCreateInfo. - // The structure must be valid when DeviceBuilder::build() is called. - template DeviceBuilder& add_pNext(T* structure) { - info.pNext_chain.push_back(reinterpret_cast(structure)); - return *this; - } - // Provide custom allocation callbacks. DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks); @@ -683,7 +677,6 @@ class DeviceBuilder { PhysicalDevice physical_device; struct DeviceInfo { VkDeviceCreateFlags flags = 0; - std::vector pNext_chain; std::vector queue_descriptions; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; } info; diff --git a/tests/bootstrap_tests.cpp b/tests/bootstrap_tests.cpp index b60ae02..81aee38 100644 --- a/tests/bootstrap_tests.cpp +++ b/tests/bootstrap_tests.cpp @@ -411,38 +411,6 @@ 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) TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") { GIVEN("A working instance") {