diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index 210dcdb..c12ea24 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -504,7 +504,6 @@ bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeat // clang-format on return true; } -} // namespace detail // finds the first queue which supports graphics operations. returns -1 if none is found int get_graphics_queue_index (std::vector const& families) { @@ -578,6 +577,7 @@ int get_present_queue_index (VkPhysicalDevice const phys_device, } return -1; } +} // namespace detail PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details ( VkPhysicalDevice phys_device) { @@ -596,12 +596,18 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (PhysicalDeviceDesc pd) { Suitable suitable = Suitable::yes; - bool dedicated_compute = get_distinct_compute_queue_index (pd.queue_families); - bool dedicated_transfer = get_distinct_transfer_queue_index (pd.queue_families); - bool present_queue = get_present_queue_index (pd.phys_device, system_info.surface, pd.queue_families); + bool dedicated_compute = detail::get_dedicated_compute_queue_index (pd.queue_families) >= 0; + bool dedicated_transfer = detail::get_dedicated_transfer_queue_index (pd.queue_families) >= 0; + bool distinct_compute = detail::get_distinct_compute_queue_index (pd.queue_families) >= 0; + bool distinct_transfer = detail::get_distinct_transfer_queue_index (pd.queue_families) >= 0; + + bool present_queue = + detail::get_present_queue_index (pd.phys_device, system_info.surface, pd.queue_families); if (criteria.require_dedicated_compute_queue && !dedicated_compute) suitable = Suitable::no; if (criteria.require_dedicated_transfer_queue && !dedicated_transfer) suitable = Suitable::no; + if (criteria.require_distinct_compute_queue && !distinct_compute) suitable = Suitable::no; + if (criteria.require_distinct_transfer_queue && !distinct_transfer) suitable = Suitable::no; if (criteria.require_present && !present_queue) suitable = Suitable::no; auto required_extensions_supported = @@ -747,6 +753,14 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::require_dedicated_compute_queue criteria.require_dedicated_compute_queue = true; return *this; } +PhysicalDeviceSelector& PhysicalDeviceSelector::require_distinct_transfer_queue () { + criteria.require_distinct_transfer_queue = true; + return *this; +} +PhysicalDeviceSelector& PhysicalDeviceSelector::require_distinct_compute_queue () { + criteria.require_distinct_compute_queue = true; + return *this; +} PhysicalDeviceSelector& PhysicalDeviceSelector::required_device_memory_size (VkDeviceSize size) { criteria.required_mem_size = size; return *this; @@ -798,6 +812,10 @@ DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device) { info.physical_device = phys_device; info.extensions = phys_device.extensions_to_enable; info.queue_families = phys_device.queue_families; + info.dedicated_compute = phys_device.dedicated_compute; + info.distinct_compute = phys_device.distinct_compute; + info.dedicated_transfer = phys_device.dedicated_transfer; + info.distinct_transfer = phys_device.distinct_transfer; } detail::Expected> DeviceBuilder::build () { @@ -807,19 +825,34 @@ detail::Expected> DeviceBuilder::build () { queue_descriptions.end (), info.queue_descriptions.begin (), info.queue_descriptions.end ()); if (queue_descriptions.size () == 0) { - int graphics = get_graphics_queue_index (info.queue_families); + int graphics = detail::get_graphics_queue_index (info.queue_families); if (graphics >= 0) { queue_descriptions.push_back ({ static_cast (graphics), 1, std::vector{ 1.0f } }); } - if (info.request_compute_queue) { - int compute = get_distinct_compute_queue_index (info.queue_families); + if (info.distinct_compute || info.dedicated_compute) { + int compute = -1; + if (info.dedicated_compute) + compute = detail::get_distinct_compute_queue_index (info.queue_families); + else if (info.distinct_compute) { + compute = detail::get_distinct_compute_queue_index (info.queue_families); + int transfer = detail::get_distinct_transfer_queue_index (info.queue_families); + if (compute == transfer && compute >= 0) compute = -1; + } + if (compute >= 0) { queue_descriptions.push_back ( { static_cast (compute), 1, std::vector{ 1.0f } }); } } - if (info.request_transfer_queue) { - int transfer = get_distinct_transfer_queue_index (info.queue_families); + if (info.distinct_transfer || info.dedicated_transfer) { + int transfer = -1; + if (info.dedicated_transfer) + transfer = detail::get_dedicated_transfer_queue_index (info.queue_families); + else if (info.distinct_transfer) { + transfer = detail::get_distinct_transfer_queue_index (info.queue_families); + int compute = detail::get_distinct_transfer_queue_index (info.queue_families); + if (transfer == compute && transfer >= 0) transfer = -1; + } if (transfer >= 0) { queue_descriptions.push_back ( { static_cast (transfer), 1, std::vector{ 1.0f } }); @@ -864,58 +897,76 @@ detail::Expected> DeviceBuilder::build () { device.queue_families = info.queue_families; return device; } - -template DeviceBuilder& DeviceBuilder::add_pNext (T* structure) { - info.pNext_chain.push_back (reinterpret_cast (structure)); - return *this; -} - DeviceBuilder& DeviceBuilder::request_dedicated_compute_queue (bool compute) { - info.request_compute_queue = compute; + info.dedicated_compute = compute; return *this; } DeviceBuilder& DeviceBuilder::request_dedicated_transfer_queue (bool transfer) { - info.request_transfer_queue = transfer; + info.dedicated_transfer = transfer; + return *this; +} +DeviceBuilder& DeviceBuilder::request_distinct_compute_queue (bool compute) { + info.distinct_compute = compute; + return *this; +} +DeviceBuilder& DeviceBuilder::request_distinct_transfer_queue (bool transfer) { + info.distinct_transfer = transfer; return *this; } DeviceBuilder& DeviceBuilder::custom_queue_setup (std::vector queue_descriptions) { info.queue_descriptions = queue_descriptions; return *this; } +template DeviceBuilder& DeviceBuilder::add_pNext (T* structure) { + info.pNext_chain.push_back (reinterpret_cast (structure)); + return *this; +} // ---- Queues ---- // +bool DeviceBuilder::has_dedicated_compute_queue () { + return detail::get_dedicated_compute_queue_index (info.queue_families) >= 0; +} +bool DeviceBuilder::has_distinct_compute_queue () { + return detail::get_distinct_compute_queue_index (info.queue_families) >= 0; +} +bool DeviceBuilder::has_dedicated_transfer_queue () { + return detail::get_dedicated_transfer_queue_index (info.queue_families) >= 0; +} +bool DeviceBuilder::has_distinct_transfer_queue () { + return detail::get_distinct_transfer_queue_index (info.queue_families) >= 0; +} + detail::Expected> get_present_queue_index (Device const& device) { - int present = get_present_queue_index ( + int present = detail::get_present_queue_index ( device.physical_device.phys_device, device.surface, device.queue_families); if (present < 0) return detail::Error{ QueueError::present_unavailable }; return static_cast (present); } detail::Expected> get_graphics_queue_index (Device const& device) { - int graphics = get_graphics_queue_index (device.queue_families); + int graphics = detail::get_graphics_queue_index (device.queue_families); if (graphics < 0) return detail::Error{ QueueError::invalid_queue_family_index }; return static_cast (graphics); } detail::Expected> get_compute_queue_index (Device const& device) { - int compute = get_distinct_compute_queue_index (device.queue_families); + int compute = detail::get_distinct_compute_queue_index (device.queue_families); if (compute < 0) return detail::Error{ QueueError::compute_unavailable }; return static_cast (compute); } detail::Expected> get_transfer_queue_index (Device const& device) { - int transfer = get_distinct_transfer_queue_index (device.queue_families); + int transfer = detail::get_distinct_transfer_queue_index (device.queue_families); if (transfer < 0) return detail::Error{ QueueError::transfer_unavailable }; return static_cast (transfer); } - VkQueue get_queue (VkDevice device, int32_t family) { VkQueue out_queue; vkGetDeviceQueue (device, family, 0, &out_queue); return out_queue; } detail::Expected> get_present_queue (Device const& device) { - int present = get_present_queue_index ( + int present = detail::get_present_queue_index ( device.physical_device.phys_device, device.surface, device.queue_families); if (present < 0) { return detail::Error{ QueueError::present_unavailable }; @@ -923,27 +974,40 @@ detail::Expected> get_present_queue (Device c return get_queue (device.device, present); } detail::Expected> get_graphics_queue (Device const& device) { - int graphics = get_graphics_queue_index (device.queue_families); + int graphics = detail::get_graphics_queue_index (device.queue_families); if (graphics < 0) { return detail::Error{ QueueError::invalid_queue_family_index }; } return get_queue (device.device, graphics); } -detail::Expected> get_compute_queue (Device const& device) { - int compute = get_distinct_compute_queue_index (device.queue_families); +detail::Expected> get_dedicated_compute_queue (Device const& device) { + int compute = detail::get_dedicated_compute_queue_index (device.queue_families); if (compute < 0) { return detail::Error{ QueueError::compute_unavailable }; } return get_queue (device.device, compute); } -detail::Expected> get_transfer_queue (Device const& device) { - int transfer = get_distinct_transfer_queue_index (device.queue_families); +detail::Expected> get_dedicated_transfer_queue (Device const& device) { + int transfer = detail::get_dedicated_transfer_queue_index (device.queue_families); + if (transfer < 0) { + return detail::Error{ QueueError::transfer_unavailable }; + } + return get_queue (device.device, transfer); +} +detail::Expected> get_distinct_compute_queue (Device const& device) { + int compute = detail::get_distinct_compute_queue_index (device.queue_families); + if (compute < 0) { + return detail::Error{ QueueError::compute_unavailable }; + } + return get_queue (device.device, compute); +} +detail::Expected> get_distinct_transfer_queue (Device const& device) { + int transfer = detail::get_distinct_transfer_queue_index (device.queue_families); if (transfer < 0) { return detail::Error{ QueueError::transfer_unavailable }; } return get_queue (device.device, transfer); } - namespace detail { VkSurfaceFormatKHR find_surface_format (std::vector const& available_formats, @@ -1000,9 +1064,9 @@ SwapchainBuilder::SwapchainBuilder (Device const& device) { info.device = device.device; info.physical_device = device.physical_device.phys_device; info.surface = device.surface; - int present = get_present_queue_index ( + int present = detail::get_present_queue_index ( device.physical_device.phys_device, device.surface, device.queue_families); - int graphics = get_graphics_queue_index (device.queue_families); + int graphics = detail::get_graphics_queue_index (device.queue_families); info.graphics_queue_index = graphics; info.present_queue_index = present; diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index baede1c..cdbb543 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -151,7 +151,7 @@ class InstanceBuilder { // Headless Mode does not load the required extensions for presentation. Defaults to false. InstanceBuilder& set_headless (bool headless = false); - // Checks if the validation layers are available and loads them if they are. + // Checks if the validation layers are available and loads them if they are. InstanceBuilder& check_and_setup_validation_layers (bool enable_validation = true); // Enables the validation layers. Will fail to create an instance if the validation layers aren't available. InstanceBuilder& must_enable_validation_layers (bool enable_validation = true); @@ -175,8 +175,8 @@ class InstanceBuilder { // Enables optional parts of the validation layers. // Parts: best practices, gpu assisted, and gpu assisted reserve binding slot. - InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable); - + InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable); + // Disables sections of the validation layers. // Options: All, shaders, thread safety, api parameters, object lifetimes, core checks, and unique handles. InstanceBuilder& add_validation_feature_disable (VkValidationFeatureDisableEXT disable); @@ -257,6 +257,10 @@ struct PhysicalDevice { VkPhysicalDeviceFeatures features{}; std::vector extensions_to_enable; std::vector queue_families; + bool dedicated_compute = false; + bool distinct_compute = false; + bool dedicated_transfer = false; + bool distinct_transfer = false; friend class PhysicalDeviceSelector; friend class DeviceBuilder; }; @@ -264,50 +268,54 @@ struct PhysicalDevice { enum class PreferredDeviceType { discrete, integrated, virtual_gpu, cpu, dont_care }; struct PhysicalDeviceSelector { public: - // Requires a vkb::Instance to construct, needed to pass instance creation info. + // Requires a vkb::Instance to construct, needed to pass instance creation info. PhysicalDeviceSelector (Instance const& instance); detail::Expected> select (); - // Set the surface in which the physical device should render to. + // Set the surface in which the physical device should render to. PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance); - // Set the desired physical device type to select. Defaults to PreferredDeviceType::discrete. + // Set the desired physical device type to select. Defaults to PreferredDeviceType::discrete. PhysicalDeviceSelector& prefer_gpu_device_type (PreferredDeviceType type = PreferredDeviceType::discrete); - // Allow fallback to a device type that isn't the preferred physical device type. Defaults to true. - PhysicalDeviceSelector& allow_fallback_gpu (bool fallback = true); + // Allow fallback to a device type that isn't the preferred physical device type. Defaults to true. + PhysicalDeviceSelector& allow_fallback_gpu (bool fallback = true); - // Require that a physical device supports presentation. Defaults to true. + // Require that a physical device supports presentation. Defaults to true. PhysicalDeviceSelector& require_present (bool require = true); - // Require a queue family that supports compute operations but not graphics nor transfer. + // Require a queue family that supports compute operations but not graphics nor transfer. PhysicalDeviceSelector& require_dedicated_compute_queue (); - // Require a queue family that supports transfer operations but not graphics nor compute. + // Require a queue family that supports transfer operations but not graphics nor compute. PhysicalDeviceSelector& require_dedicated_transfer_queue (); + // Require a queue family that supports compute operations but not graphics. + PhysicalDeviceSelector& require_distinct_compute_queue (); + // Require a queue family that supports transfer operations but not graphics. + PhysicalDeviceSelector& require_distinct_transfer_queue (); - // Require a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available. + // Require a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available. PhysicalDeviceSelector& required_device_memory_size (VkDeviceSize size); - // Prefer a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available. + // Prefer a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available. PhysicalDeviceSelector& desired_device_memory_size (VkDeviceSize size); - // Require a physical device which supports a specific extension. + // Require a physical device which supports a specific extension. PhysicalDeviceSelector& add_required_extension (const char* extension); - // Require a physical device which supports a set of extensions. + // Require a physical device which supports a set of extensions. PhysicalDeviceSelector& add_required_extensions (std::vector extensions); - // Prefer a physical device which supports a specific extension. + // Prefer a physical device which supports a specific extension. PhysicalDeviceSelector& add_desired_extension (const char* extension); - // Prefer a physical device which supports a set of extensions. + // Prefer a physical device which supports a set of extensions. PhysicalDeviceSelector& add_desired_extensions (std::vector extensions); - // Prefer a physical device that supports a (major, minor) version of vulkan. + // Prefer a physical device that supports a (major, minor) version of vulkan. PhysicalDeviceSelector& set_desired_version (uint32_t major, uint32_t minor); - // Require a physical device that supports a (major, minor) version of vulkan. Default is Vulkan 1.0. + // Require a physical device that supports a (major, minor) version of vulkan. Default is Vulkan 1.0. PhysicalDeviceSelector& set_minimum_version (uint32_t major = 1, uint32_t minor = 0); - // Require a physical device which supports the features in VkPhysicalDeviceFeatures. + // Require a physical device which supports the features in VkPhysicalDeviceFeatures. PhysicalDeviceSelector& set_required_features (VkPhysicalDeviceFeatures features); - // Ignore all criteria and choose the first physical device that is available. - // Only use when: The first gpu in the list may be set by global user preferences and an application may wish to respect it. + // Ignore all criteria and choose the first physical device that is available. + // Only use when: The first gpu in the list may be set by global user preferences and an application may wish to respect it. PhysicalDeviceSelector& select_first_device_unconditionally (bool unconditionally = true); private: @@ -333,6 +341,8 @@ struct PhysicalDeviceSelector { bool require_present = true; bool require_dedicated_transfer_queue = false; bool require_dedicated_compute_queue = false; + bool require_distinct_transfer_queue = false; + bool require_distinct_compute_queue = false; VkDeviceSize required_mem_size = 0; VkDeviceSize desired_mem_size = 0; @@ -380,17 +390,27 @@ class DeviceBuilder { detail::Expected> build (); - // Require a queue family that supports compute operations but not graphics nor transfer. + bool has_dedicated_compute_queue(); + bool has_distinct_compute_queue(); + bool has_dedicated_transfer_queue(); + bool has_distinct_transfer_queue(); + + // Require a queue family that supports compute operations but not graphics nor transfer. DeviceBuilder& request_dedicated_compute_queue (bool compute = true); - // Require a queue family that supports transfer operations but not graphics nor compute. + // Require a queue family that supports transfer operations but not graphics nor compute. DeviceBuilder& request_dedicated_transfer_queue (bool transfer = true); + // Require a queue family that supports compute operations but not graphics. + DeviceBuilder& request_distinct_compute_queue (bool compute = true); + // Require a queue family that supports transfer operations but not graphics. + DeviceBuilder& request_distinct_transfer_queue (bool transfer = true); + // For Advanced Users: specify the exact list of VkDeviceQueueCreateInfo's needed for the application. - // If a custom queue setup is provided, getting the queues and queue indexes is up to the applicatoin. + // If a custom queue setup is provided, getting the queues and queue indexes is up to the applicatoin. DeviceBuilder& custom_queue_setup (std::vector queue_descriptions); - // For Advanced Users: Add a structure to the pNext chain of VkDeviceCreateInfo. - // The structure must be valid when DeviceBuilder::build() is called. + // For Advanced Users: 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); private: @@ -401,12 +421,14 @@ class DeviceBuilder { std::vector extensions; std::vector queue_families; std::vector queue_descriptions; - bool request_compute_queue = false; - bool request_transfer_queue = false; + bool dedicated_compute = false; + bool distinct_compute = false; + bool dedicated_transfer = false; + bool distinct_transfer = false; } info; }; -// ---- Getting Queues ---- // +// ---- Queues ---- // enum class QueueError { present_unavailable, diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index c79cb66..d455ee8 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -148,6 +148,14 @@ int test_device_creation () { return 0; } +// TODO +// Migrate to Catch2 +// Getting queues +// get dedicated vs distinct compute queues +// Swapchain creation +// Swapchain recreation +// changing present modes and/or image formats + int main () { test_happy_path (); test_instance_basic ();