Add queue selection tests and refactor internal code a bit

This commit is contained in:
Charles Giessen 2021-04-01 16:20:39 -06:00 committed by Charles Giessen
parent 36eff8fa42
commit 045b1e7b0f
3 changed files with 131 additions and 58 deletions

View File

@ -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<VkQueueFamilyProperties> 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<VkQueueFamilyProperties> const& families, VkQueueFlags desired_flags) {
for (uint32_t i = 0; i < static_cast<uint32_t>(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<VkQueueFamilyProperties> 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<VkQueueFamilyProperties> const& families,
VkQueueFlags desired_flags,
VkQueueFlags undesired_flags) {
uint32_t index = QUEUE_INDEX_MAX_VALUE;
for (uint32_t i = 0; i < static_cast<uint32_t>(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<VkQueueFamilyProperties> 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<VkQueueFamilyProperties> const& families,
VkQueueFlags desired_flags,
VkQueueFlags undesired_flags) {
for (uint32_t i = 0; i < static_cast<uint32_t>(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<VkQueueFamilyProperties> const& families) {
for (uint32_t i = 0; i < static_cast<uint32_t>(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<VkQueueFamilyProperties> const& families) {
for (uint32_t i = 0; i < static_cast<uint32_t>(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<VkQueueFamilyProperties> PhysicalDevice::get_queue_families() const {
return queue_families;
@ -1329,17 +1308,17 @@ detail::Result<uint32_t> Device::get_queue_index(QueueType type) const {
return detail::Result<uint32_t>{ 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<uint32_t>{ 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<uint32_t>{ 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<uint32_t>{ QueueError::transfer_unavailable };
break;
@ -1352,12 +1331,12 @@ detail::Result<uint32_t> 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<uint32_t>{ 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<uint32_t>{ QueueError::transfer_unavailable };
break;
@ -1660,7 +1639,7 @@ SwapchainBuilder::SwapchainBuilder(VkPhysicalDevice const physical_device,
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties>(
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);
}

View File

@ -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

94
tests/unit_tests.cpp Normal file
View File

@ -0,0 +1,94 @@
#include <catch2/catch.hpp>
#include "VkBootstrap.cpp"
TEST_CASE("Single Queue Device", "[UnitTests.queue_selection_logic]") {
std::vector<VkQueueFamilyProperties> 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<VkQueueFamilyProperties> 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<VkQueueFamilyProperties> 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<VkQueueFamilyProperties> 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<VkQueueFamilyProperties> 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());
}