Refactor of queue selection and getting

This commit is contained in:
Charles Giessen 2020-03-07 17:02:01 -07:00
parent 83fd58348b
commit 1014c836cb
3 changed files with 128 additions and 210 deletions

View File

@ -75,13 +75,14 @@ int device_initialization (Init& init) {
}
int get_queues (Init& init, RenderData& data) {
auto gq = vkb::get_graphics_queue (init.device);
auto gq = init.device.get_queue (vkb::QueueType::graphics);
if (!gq.has_value ()) {
std::cout << "failed to get graphics queue\n";
return -1;
}
data.graphics_queue = gq.value ();
auto pq = vkb::get_present_queue (init.device);
auto pq = init.device.get_queue (vkb::QueueType::present);
if (!pq.has_value ()) {
std::cout << "failed to get present queue\n";
return -1;
@ -314,7 +315,7 @@ int create_framebuffers (Init& init, RenderData& data) {
int create_command_pool (Init& init, RenderData& data) {
VkCommandPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.queueFamilyIndex = vkb::get_graphics_queue_index (init.device).value ();
pool_info.queueFamilyIndex = init.device.get_queue_index (vkb::QueueType::graphics).value ();
if (vkCreateCommandPool (init.device.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) {
return -1; // failed to create command pool

View File

@ -840,7 +840,92 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::select_first_device_unconditiona
return *this;
}
bool PhysicalDevice::has_dedicated_compute_queue () {
return detail::get_dedicated_compute_queue_index (queue_families) >= 0;
}
bool PhysicalDevice::has_separate_compute_queue () {
return detail::get_separate_compute_queue_index (queue_families) >= 0;
}
bool PhysicalDevice::has_dedicated_transfer_queue () {
return detail::get_dedicated_transfer_queue_index (queue_families) >= 0;
}
bool PhysicalDevice::has_separate_transfer_queue () {
return detail::get_separate_transfer_queue_index (queue_families) >= 0;
}
// ---- Queues ---- //
const char* to_string (QueueError err) {
switch (err) {
case QueueError::present_unavailable:
return "present_unavailable";
case QueueError::graphics_unavailable:
return "graphics_unavailable";
case QueueError::compute_unavailable:
return "compute_unavailable";
case QueueError::transfer_unavailable:
return "transfer_unavailable";
case QueueError::queue_index_out_of_range:
return "queue_index_out_of_range";
case QueueError::invalid_queue_family_index:
return "invalid_queue_family_index";
default:
return "";
}
}
detail::Expected<int32_t, detail::Error<QueueError>> Device::get_queue_index (QueueType type) const {
int index = -1;
if (type == QueueType::present) {
index = detail::get_present_queue_index (physical_device.phys_device, surface, queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::present_unavailable };
} else if (type == QueueType::graphics) {
index = detail::get_graphics_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::graphics_unavailable };
} else if (type == QueueType::compute) {
index = detail::get_separate_compute_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable };
} else if (type == QueueType::transfer) {
index = detail::get_separate_transfer_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable };
} else if (index == -1) {
return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
}
return index;
}
detail::Expected<int32_t, detail::Error<QueueError>> Device::get_dedicated_queue_index (QueueType type) const {
int index = -1;
if (type == QueueType::compute) {
index = detail::get_dedicated_compute_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable };
} else if (type == QueueType::transfer) {
index = detail::get_dedicated_transfer_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable };
} else if (index == -1) {
return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
}
return index;
}
namespace detail {
VkQueue get_queue (VkDevice device, int32_t family) {
VkQueue out_queue;
vkGetDeviceQueue (device, family, 0, &out_queue);
return out_queue;
}
} // namespace detail
detail::Expected<VkQueue, detail::Error<QueueError>> Device::get_queue (QueueType type) const {
auto index = get_queue_index (type);
if (!index.has_value ()) return index.error ();
return detail::get_queue (device, index.value ());
}
detail::Expected<VkQueue, detail::Error<QueueError>> Device::get_dedicated_queue (QueueType type) const {
auto index = get_dedicated_queue_index (type);
if (!index.has_value ()) return index.error ();
return detail::get_queue (device, index.value ());
}
// ---- Device ---- //
const char* to_string (DeviceError err) {
switch (err) {
case DeviceError::failed_create_device:
@ -858,10 +943,6 @@ 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.separate_compute = phys_device.separate_compute;
info.dedicated_transfer = phys_device.dedicated_transfer;
info.separate_transfer = phys_device.separate_transfer;
}
detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
@ -871,38 +952,8 @@ detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
queue_descriptions.end (), info.queue_descriptions.begin (), info.queue_descriptions.end ());
if (queue_descriptions.size () == 0) {
int graphics = detail::get_graphics_queue_index (info.queue_families);
if (graphics >= 0) {
queue_descriptions.push_back ({ static_cast<uint32_t> (graphics), 1, std::vector<float>{ 1.0f } });
}
if (info.separate_compute || info.dedicated_compute) {
int compute = -1;
if (info.dedicated_compute)
compute = detail::get_separate_compute_queue_index (info.queue_families);
else if (info.separate_compute) {
compute = detail::get_separate_compute_queue_index (info.queue_families);
int transfer = detail::get_separate_transfer_queue_index (info.queue_families);
if (compute == transfer && compute >= 0) compute = -1;
}
if (compute >= 0) {
queue_descriptions.push_back (
{ static_cast<uint32_t> (compute), 1, std::vector<float>{ 1.0f } });
}
}
if (info.separate_transfer || info.dedicated_transfer) {
int transfer = -1;
if (info.dedicated_transfer)
transfer = detail::get_dedicated_transfer_queue_index (info.queue_families);
else if (info.separate_transfer) {
transfer = detail::get_separate_transfer_queue_index (info.queue_families);
int compute = detail::get_separate_transfer_queue_index (info.queue_families);
if (transfer == compute && transfer >= 0) transfer = -1;
}
if (transfer >= 0) {
queue_descriptions.push_back (
{ static_cast<uint32_t> (transfer), 1, std::vector<float>{ 1.0f } });
}
for (uint32_t i = 0; i < info.queue_families.size (); i++) {
queue_descriptions.push_back ({ i, 1, std::vector<float>{ 1.0f } });
}
}
@ -944,22 +995,6 @@ detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
device.allocation_callbacks = info.allocation_callbacks;
return device;
}
DeviceBuilder& DeviceBuilder::request_dedicated_compute_queue (bool compute) {
info.dedicated_compute = compute;
return *this;
}
DeviceBuilder& DeviceBuilder::request_dedicated_transfer_queue (bool transfer) {
info.dedicated_transfer = transfer;
return *this;
}
DeviceBuilder& DeviceBuilder::request_separate_compute_queue (bool compute) {
info.separate_compute = compute;
return *this;
}
DeviceBuilder& DeviceBuilder::request_separate_transfer_queue (bool transfer) {
info.separate_transfer = transfer;
return *this;
}
DeviceBuilder& DeviceBuilder::custom_queue_setup (std::vector<CustomQueueDescription> queue_descriptions) {
info.queue_descriptions = queue_descriptions;
return *this;
@ -973,109 +1008,6 @@ DeviceBuilder& DeviceBuilder::set_allocation_callbacks (VkAllocationCallbacks* c
return *this;
}
// ---- Queues ---- //
const char* to_string (QueueError err) {
switch (err) {
case QueueError::present_unavailable:
return "present_unavailable";
case QueueError::compute_unavailable:
return "compute_unavailable";
case QueueError::transfer_unavailable:
return "transfer_unavailable";
case QueueError::queue_index_out_of_range:
return "queue_index_out_of_range";
case QueueError::invalid_queue_family_index:
return "invalid_queue_family_index";
default:
return "";
}
}
bool DeviceBuilder::has_dedicated_compute_queue () {
return detail::get_dedicated_compute_queue_index (info.queue_families) >= 0;
}
bool DeviceBuilder::has_separate_compute_queue () {
return detail::get_separate_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_separate_transfer_queue () {
return detail::get_separate_transfer_queue_index (info.queue_families) >= 0;
}
detail::Expected<uint32_t, detail::Error<QueueError>> get_present_queue_index (Device const& device) {
int present = detail::get_present_queue_index (
device.physical_device.phys_device, device.surface, device.queue_families);
if (present < 0) return detail::Error<QueueError>{ QueueError::present_unavailable };
return static_cast<uint32_t> (present);
}
detail::Expected<uint32_t, detail::Error<QueueError>> get_graphics_queue_index (Device const& device) {
int graphics = detail::get_graphics_queue_index (device.queue_families);
if (graphics < 0) return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
return static_cast<uint32_t> (graphics);
}
detail::Expected<uint32_t, detail::Error<QueueError>> get_compute_queue_index (Device const& device) {
int compute = detail::get_separate_compute_queue_index (device.queue_families);
if (compute < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable };
return static_cast<uint32_t> (compute);
}
detail::Expected<uint32_t, detail::Error<QueueError>> get_transfer_queue_index (Device const& device) {
int transfer = detail::get_separate_transfer_queue_index (device.queue_families);
if (transfer < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable };
return static_cast<uint32_t> (transfer);
}
VkQueue get_queue (VkDevice device, int32_t family) {
VkQueue out_queue;
vkGetDeviceQueue (device, family, 0, &out_queue);
return out_queue;
}
detail::Expected<VkQueue, detail::Error<QueueError>> get_present_queue (Device const& device) {
int present = detail::get_present_queue_index (
device.physical_device.phys_device, device.surface, device.queue_families);
if (present < 0) {
return detail::Error<QueueError>{ QueueError::present_unavailable };
}
return get_queue (device.device, present);
}
detail::Expected<VkQueue, detail::Error<QueueError>> get_graphics_queue (Device const& device) {
int graphics = detail::get_graphics_queue_index (device.queue_families);
if (graphics < 0) {
return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
}
return get_queue (device.device, graphics);
}
detail::Expected<VkQueue, detail::Error<QueueError>> 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>{ QueueError::compute_unavailable };
}
return get_queue (device.device, compute);
}
detail::Expected<VkQueue, detail::Error<QueueError>> 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>{ QueueError::transfer_unavailable };
}
return get_queue (device.device, transfer);
}
detail::Expected<VkQueue, detail::Error<QueueError>> get_separate_compute_queue (Device const& device) {
int compute = detail::get_separate_compute_queue_index (device.queue_families);
if (compute < 0) {
return detail::Error<QueueError>{ QueueError::compute_unavailable };
}
return get_queue (device.device, compute);
}
detail::Expected<VkQueue, detail::Error<QueueError>> get_separate_transfer_queue (Device const& device) {
int transfer = detail::get_separate_transfer_queue_index (device.queue_families);
if (transfer < 0) {
return detail::Error<QueueError>{ QueueError::transfer_unavailable };
}
return get_queue (device.device, transfer);
}
namespace detail {
VkSurfaceFormatKHR find_surface_format (std::vector<VkSurfaceFormatKHR> const& available_formats,
std::vector<VkSurfaceFormatKHR> const& desired_formats) {
@ -1146,12 +1078,11 @@ SwapchainBuilder::SwapchainBuilder (Device const& device) {
info.device = device.device;
info.physical_device = device.physical_device.phys_device;
info.surface = device.surface;
int present = detail::get_present_queue_index (
device.physical_device.phys_device, device.surface, device.queue_families);
int graphics = detail::get_graphics_queue_index (device.queue_families);
info.graphics_queue_index = graphics;
info.present_queue_index = present;
auto present = device.get_queue_index (QueueType::present);
auto graphics = device.get_queue_index (QueueType::graphics);
// TODO: handle error of queue's not available
info.graphics_queue_index = present.value ();
info.present_queue_index = graphics.value ();
}
SwapchainBuilder::SwapchainBuilder (VkPhysicalDevice const physical_device,

View File

@ -268,14 +268,20 @@ struct PhysicalDevice {
VkPhysicalDevice phys_device = VK_NULL_HANDLE;
VkSurfaceKHR surface = VK_NULL_HANDLE;
// Has a queue family that supports compute operations but not graphics nor transfer.
bool has_dedicated_compute_queue ();
// Has a queue family that supports transfer operations but not graphics nor compute.
bool has_dedicated_transfer_queue ();
// Has a queue family that supports transfer operations but not graphics.
bool has_separate_compute_queue ();
// Has a queue family that supports transfer operations but not graphics.
bool has_separate_transfer_queue ();
private:
VkPhysicalDeviceFeatures features{};
std::vector<const char*> extensions_to_enable;
std::vector<VkQueueFamilyProperties> queue_families;
bool dedicated_compute = false;
bool separate_compute = false;
bool dedicated_transfer = false;
bool separate_transfer = false;
friend class PhysicalDeviceSelector;
friend class DeviceBuilder;
};
@ -304,10 +310,12 @@ class PhysicalDeviceSelector {
// 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.
PhysicalDeviceSelector& require_dedicated_compute_queue ();
// 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_separate_compute_queue ();
// Require a queue family that supports transfer operations but not graphics.
@ -384,6 +392,19 @@ class PhysicalDeviceSelector {
Suitable is_device_suitable (PhysicalDeviceDesc phys_device);
};
// ---- Queues ---- //
enum class QueueType { present, graphics, compute, transfer };
enum class QueueError {
present_unavailable,
graphics_unavailable,
compute_unavailable,
transfer_unavailable,
queue_index_out_of_range,
invalid_queue_family_index
};
const char* to_string (QueueError err);
// ---- Device ---- //
enum class DeviceError {
failed_create_device,
@ -397,6 +418,12 @@ struct Device {
VkSurfaceKHR surface = VK_NULL_HANDLE;
std::vector<VkQueueFamilyProperties> queue_families;
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
detail::Expected<int32_t, detail::Error<QueueError>> get_queue_index (QueueType type) const;
detail::Expected<int32_t, detail::Error<QueueError>> get_dedicated_queue_index (QueueType type) const;
detail::Expected<VkQueue, detail::Error<QueueError>> get_queue (QueueType type) const;
detail::Expected<VkQueue, detail::Error<QueueError>> get_dedicated_queue (QueueType type) const;
};
void destroy_device (Device device);
@ -415,26 +442,11 @@ class DeviceBuilder {
detail::Expected<Device, detail::Error<DeviceError>> build ();
bool has_dedicated_compute_queue ();
bool has_separate_compute_queue ();
bool has_dedicated_transfer_queue ();
bool has_separate_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.
DeviceBuilder& request_dedicated_transfer_queue (bool transfer = true);
// Require a queue family that supports compute operations but not graphics.
DeviceBuilder& request_separate_compute_queue (bool compute = true);
// Require a queue family that supports transfer operations but not graphics.
DeviceBuilder& request_separate_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 application.
DeviceBuilder& custom_queue_setup (std::vector<CustomQueueDescription> queue_descriptions);
// For Advanced Users: Add a structure to the pNext chain of VkDeviceCreateInfo.
// 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);
@ -449,36 +461,10 @@ class DeviceBuilder {
std::vector<const char*> extensions;
std::vector<VkQueueFamilyProperties> queue_families;
std::vector<CustomQueueDescription> queue_descriptions;
bool dedicated_compute = false;
bool separate_compute = false;
bool dedicated_transfer = false;
bool separate_transfer = false;
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
} info;
};
// ---- Queues ---- //
enum class QueueError {
present_unavailable,
compute_unavailable,
transfer_unavailable,
queue_index_out_of_range,
invalid_queue_family_index
};
const char* to_string (QueueError err);
detail::Expected<uint32_t, detail::Error<QueueError>> get_present_queue_index (Device const& device);
detail::Expected<uint32_t, detail::Error<QueueError>> get_graphics_queue_index (Device const& device);
detail::Expected<uint32_t, detail::Error<QueueError>> get_compute_queue_index (Device const& device);
detail::Expected<uint32_t, detail::Error<QueueError>> get_transfer_queue_index (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> get_present_queue (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> get_graphics_queue (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> get_compute_queue (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> get_transfer_queue (Device const& device);
// ---- Swapchain ---- //
enum class SwapchainError {