From 045b1e7b0f769e3d5ffe3f0366b4276b58a81178 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Thu, 1 Apr 2021 16:20:39 -0600 Subject: [PATCH] Add queue selection tests and refactor internal code a bit --- src/VkBootstrap.cpp | 93 +++++++++++++++++-------------------------- tests/CMakeLists.txt | 2 +- tests/unit_tests.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 58 deletions(-) create mode 100644 tests/unit_tests.cpp diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index 531c36c..bbd87f3 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -927,65 +927,44 @@ bool supports_features(VkPhysicalDeviceFeatures supported, return true; } // clang-format on -// finds the first queue which supports graphics operations. returns QUEUE_INDEX_MAX_VALUE if none is found -uint32_t get_graphics_queue_index(std::vector const& families) { +// Finds the first queue which supports the desired operations. Returns QUEUE_INDEX_MAX_VALUE if none is found +uint32_t get_first_queue_index(std::vector const& families, VkQueueFlags desired_flags) { for (uint32_t i = 0; i < static_cast(families.size()); i++) { - if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) return i; + if (families[i].queueFlags & desired_flags) return i; } return QUEUE_INDEX_MAX_VALUE; } -// finds a compute queue which is separate from the graphics queue and tries to find one without -// transfer support returns QUEUE_INDEX_MAX_VALUE if none is found -uint32_t get_separate_compute_queue_index(std::vector const& families) { - uint32_t compute = QUEUE_INDEX_MAX_VALUE; +// Finds the queue which is separate from the graphics queue and has the desired flag and not the +// undesired flag, but will select it if no better options are available compute support. Returns +// QUEUE_INDEX_MAX_VALUE if none is found. +uint32_t get_separate_queue_index(std::vector const& families, + VkQueueFlags desired_flags, + VkQueueFlags undesired_flags) { + uint32_t index = QUEUE_INDEX_MAX_VALUE; for (uint32_t i = 0; i < static_cast(families.size()); i++) { - if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) && - ((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) { - if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0) { + if ((families[i].queueFlags & desired_flags) && ((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) { + if ((families[i].queueFlags & undesired_flags) == 0) { return i; } else { - compute = i; + index = i; } } } - return compute; + return index; } -// finds a transfer queue which is separate from the graphics queue and tries to find one without -// compute support returns QUEUE_INDEX_MAX_VALUE if none is found -uint32_t get_separate_transfer_queue_index(std::vector const& families) { - uint32_t transfer = QUEUE_INDEX_MAX_VALUE; + +// finds the first queue which supports only the desired flag (not graphics or transfer). Returns QUEUE_INDEX_MAX_VALUE if none is found. +uint32_t get_dedicated_queue_index(std::vector const& families, + VkQueueFlags desired_flags, + VkQueueFlags undesired_flags) { for (uint32_t i = 0; i < static_cast(families.size()); i++) { - if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) && - ((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) { - if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0) { - return i; - } else { - transfer = i; - } - } - } - return transfer; -} -// finds the first queue which supports only compute (not graphics or transfer). returns QUEUE_INDEX_MAX_VALUE if none is found -uint32_t get_dedicated_compute_queue_index(std::vector const& families) { - for (uint32_t i = 0; i < static_cast(families.size()); i++) { - if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) && - (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && - (families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0) - return i; - } - return QUEUE_INDEX_MAX_VALUE; -} -// finds the first queue which supports only transfer (not graphics or compute). returns QUEUE_INDEX_MAX_VALUE if none is found -uint32_t get_dedicated_transfer_queue_index(std::vector const& families) { - for (uint32_t i = 0; i < static_cast(families.size()); i++) { - if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) && - (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && - (families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0) + if ((families[i].queueFlags & desired_flags) && (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && + (families[i].queueFlags & undesired_flags) == 0) return i; } return QUEUE_INDEX_MAX_VALUE; } + // finds the first queue which supports presenting. returns QUEUE_INDEX_MAX_VALUE if none is found uint32_t get_present_queue_index(VkPhysicalDevice const phys_device, VkSurfaceKHR const surface, @@ -1052,13 +1031,13 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(Phys if (criteria.desired_version > pd.device_properties.apiVersion) suitable = Suitable::partial; bool dedicated_compute = - detail::get_dedicated_compute_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + detail::get_dedicated_queue_index(pd.queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE; bool dedicated_transfer = - detail::get_dedicated_transfer_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + detail::get_dedicated_queue_index(pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE; bool separate_compute = - detail::get_separate_compute_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE; bool separate_transfer = - detail::get_separate_transfer_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE; bool present_queue = detail::get_present_queue_index(pd.phys_device, instance_info.surface, pd.queue_families) != @@ -1303,16 +1282,16 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::select_first_device_unconditiona } bool PhysicalDevice::has_dedicated_compute_queue() const { - return detail::get_dedicated_compute_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } bool PhysicalDevice::has_separate_compute_queue() const { - return detail::get_separate_compute_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + return detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } bool PhysicalDevice::has_dedicated_transfer_queue() const { - return detail::get_dedicated_transfer_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } bool PhysicalDevice::has_separate_transfer_queue() const { - return detail::get_separate_transfer_queue_index(queue_families) != detail::QUEUE_INDEX_MAX_VALUE; + return detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } std::vector PhysicalDevice::get_queue_families() const { return queue_families; @@ -1329,17 +1308,17 @@ detail::Result Device::get_queue_index(QueueType type) const { return detail::Result{ QueueError::present_unavailable }; break; case QueueType::graphics: - index = detail::get_graphics_queue_index(queue_families); + index = detail::get_first_queue_index(queue_families, VK_QUEUE_GRAPHICS_BIT); if (index == detail::QUEUE_INDEX_MAX_VALUE) return detail::Result{ QueueError::graphics_unavailable }; break; case QueueType::compute: - index = detail::get_separate_compute_queue_index(queue_families); + index = detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT); if (index == detail::QUEUE_INDEX_MAX_VALUE) return detail::Result{ QueueError::compute_unavailable }; break; case QueueType::transfer: - index = detail::get_separate_transfer_queue_index(queue_families); + index = detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT); if (index == detail::QUEUE_INDEX_MAX_VALUE) return detail::Result{ QueueError::transfer_unavailable }; break; @@ -1352,12 +1331,12 @@ detail::Result Device::get_dedicated_queue_index(QueueType type) const uint32_t index = detail::QUEUE_INDEX_MAX_VALUE; switch (type) { case QueueType::compute: - index = detail::get_dedicated_compute_queue_index(queue_families); + index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT); if (index == detail::QUEUE_INDEX_MAX_VALUE) return detail::Result{ QueueError::compute_unavailable }; break; case QueueType::transfer: - index = detail::get_dedicated_transfer_queue_index(queue_families); + index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT); if (index == detail::QUEUE_INDEX_MAX_VALUE) return detail::Result{ QueueError::transfer_unavailable }; break; @@ -1660,7 +1639,7 @@ SwapchainBuilder::SwapchainBuilder(VkPhysicalDevice const physical_device, auto queue_families = detail::get_vector_noerror( detail::vulkan_functions().fp_vkGetPhysicalDeviceQueueFamilyProperties, physical_device); if (graphics_queue_index == detail::QUEUE_INDEX_MAX_VALUE) - info.graphics_queue_index = detail::get_graphics_queue_index(queue_families); + info.graphics_queue_index = detail::get_first_queue_index(queue_families, VK_QUEUE_GRAPHICS_BIT); if (present_queue_index == detail::QUEUE_INDEX_MAX_VALUE) info.present_queue_index = detail::get_present_queue_index(physical_device, surface, queue_families); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b9f3e87..5a58dbe 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(vk-bootstrap-test main.cpp bootstrap_tests.cpp error_code_tests.cpp) +add_executable(vk-bootstrap-test main.cpp bootstrap_tests.cpp error_code_tests.cpp unit_tests.cpp) target_link_libraries(vk-bootstrap-test PRIVATE vk-bootstrap diff --git a/tests/unit_tests.cpp b/tests/unit_tests.cpp new file mode 100644 index 0000000..e43c0bb --- /dev/null +++ b/tests/unit_tests.cpp @@ -0,0 +1,94 @@ +#include + +#include "VkBootstrap.cpp" + + +TEST_CASE("Single Queue Device", "[UnitTests.queue_selection_logic]") { + std::vector families = { VkQueueFamilyProperties{ + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } } }; + + REQUIRE(0 == vkb::detail::get_first_queue_index(families, VK_QUEUE_GRAPHICS_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_separate_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_separate_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); +} + +TEST_CASE("Dedicated Compute Queue, Separate Transfer", "[UnitTests.queue_selection_logic]") { + SECTION("Dedicated Queue First") { + std::vector families = { + VkQueueFamilyProperties{ + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } } + }; + + REQUIRE(0 == vkb::detail::get_first_queue_index(families, VK_QUEUE_GRAPHICS_BIT)); + REQUIRE(1 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(2 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + REQUIRE(1 == vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + } + SECTION("Dedicated Queue Last") { + std::vector families = { + VkQueueFamilyProperties{ + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } } + }; + + REQUIRE(0 == vkb::detail::get_first_queue_index(families, VK_QUEUE_GRAPHICS_BIT)); + REQUIRE(2 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(1 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + REQUIRE(2 == vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + } +} + +TEST_CASE("Dedicated Transfer Queue, Separate Compute", "[UnitTests.queue_selection_logic]") { + SECTION("Dedicated Queue First") { + std::vector families = { + VkQueueFamilyProperties{ + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_TRANSFER_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } } + }; + + REQUIRE(0 == vkb::detail::get_first_queue_index(families, VK_QUEUE_GRAPHICS_BIT)); + REQUIRE(2 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(1 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(1 == vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + } + SECTION("Dedicated Queue Last") { + std::vector families = { + VkQueueFamilyProperties{ + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } }, + VkQueueFamilyProperties{ VK_QUEUE_TRANSFER_BIT, 1, 0, VkExtent3D{ 1, 1, 1 } } + }; + + REQUIRE(0 == vkb::detail::get_first_queue_index(families, VK_QUEUE_GRAPHICS_BIT)); + REQUIRE(1 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(2 == vkb::detail::get_separate_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE == + vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT)); + REQUIRE(2 == vkb::detail::get_dedicated_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT)); + } +} + +TEST_CASE("Queue Selection logic", "[VkBootstrap.queue_logic]") { + vkb::InstanceBuilder builder; + + auto instance_ret = builder.request_validation_layers().build(); + REQUIRE(instance_ret.has_value()); + + vkb::destroy_instance(instance_ret.value()); +} \ No newline at end of file