Made compute and transfer queues have distinct and dedicated options. This means you can choose between

whether you select a compute/transfer queue that can alias and one that cannot.
It is due to some hardware having dedicated compute or dedicated transfer but not both.

Also added some todo's for what to test.
This commit is contained in:
Charles Giessen 2020-02-18 19:45:22 -07:00
parent 37656d311a
commit 6f0184bdbe
3 changed files with 155 additions and 61 deletions

View File

@ -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<VkQueueFamilyProperties> 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<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
@ -807,19 +825,34 @@ 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 = 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<uint32_t> (graphics), 1, std::vector<float>{ 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<uint32_t> (compute), 1, std::vector<float>{ 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<uint32_t> (transfer), 1, std::vector<float>{ 1.0f } });
@ -864,58 +897,76 @@ detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
device.queue_families = info.queue_families;
return device;
}
template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure) {
info.pNext_chain.push_back (reinterpret_cast<VkBaseOutStructure*> (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<CustomQueueDescription> queue_descriptions) {
info.queue_descriptions = queue_descriptions;
return *this;
}
template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure) {
info.pNext_chain.push_back (reinterpret_cast<VkBaseOutStructure*> (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<uint32_t, detail::Error<QueueError>> 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>{ 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 = get_graphics_queue_index (device.queue_families);
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 = 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>{ 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 = 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>{ 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 = 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>{ QueueError::present_unavailable };
@ -923,27 +974,40 @@ detail::Expected<VkQueue, detail::Error<QueueError>> get_present_queue (Device c
return get_queue (device.device, present);
}
detail::Expected<VkQueue, detail::Error<QueueError>> 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>{ QueueError::invalid_queue_family_index };
}
return get_queue (device.device, graphics);
}
detail::Expected<VkQueue, detail::Error<QueueError>> get_compute_queue (Device const& device) {
int compute = get_distinct_compute_queue_index (device.queue_families);
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_transfer_queue (Device const& device) {
int transfer = get_distinct_transfer_queue_index (device.queue_families);
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_distinct_compute_queue (Device const& device) {
int compute = detail::get_distinct_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_distinct_transfer_queue (Device const& device) {
int transfer = detail::get_distinct_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,
@ -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;

View File

@ -175,7 +175,7 @@ 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.
@ -257,6 +257,10 @@ struct PhysicalDevice {
VkPhysicalDeviceFeatures features{};
std::vector<const char*> extensions_to_enable;
std::vector<VkQueueFamilyProperties> 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<PhysicalDevice, detail::Error<PhysicalDeviceError>> 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<const char*> 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<const char*> 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<Device, detail::Error<DeviceError>> 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<CustomQueueDescription> 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 <typename T> DeviceBuilder& add_pNext (T* structure);
private:
@ -401,12 +421,14 @@ class DeviceBuilder {
std::vector<const char*> extensions;
std::vector<VkQueueFamilyProperties> queue_families;
std::vector<CustomQueueDescription> 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,

View File

@ -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 ();