mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-21 23:14:35 +00:00
Add new Queue query API
The original queue query API has shortcomings which cause confusion and make it harder to do the things people want with vk-bootstrap. Design features of the new API: * Choose a queue given a combination of queue types - Instead of only choosing based on a single queue type * Allow picking the first or 'preferred' queue for any given combination of queue types * Allow picking a present queue with a specific surface handle - Instead of only using the surface the PhysicalDevice was selected with * Dont need to update the library to support new queue types over time
This commit is contained in:
parent
be0df09b3a
commit
f290028cb5
@ -1,6 +1,6 @@
|
||||
# Getting Started
|
||||
|
||||
`vk-bootstrap` reduces the complexity of setting up a vulkan application by simplifying the three initial steps; instance creation, Physical device selection, and device creation.
|
||||
`vk-bootstrap` reduces the complexity of setting up a vulkan application by simplifying the three initial steps; instance creation, Physical device selection, and device creation.
|
||||
|
||||
## Instance Creation
|
||||
|
||||
@ -16,17 +16,17 @@ Because creating an instance may fail, the builder returns an 'Result' type. Thi
|
||||
if (!instance_builder_return) {
|
||||
std::cerr << "Failed to create Vulkan instance. Error: " << instance_builder_return.error().message() << "\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
```
|
||||
Once any possible errors have been dealt with, we can pull the `vkb::Instance` struct out of the `Result`.
|
||||
Once any possible errors have been dealt with, we can pull the `vkb::Instance` struct out of the `Result`.
|
||||
```cpp
|
||||
vkb::Instance vkb_instance = instance_builder_return.value();
|
||||
```
|
||||
This is enough to create a usable `VkInstance` handle but many will want to customize it a bit. To configure instance creation, simply call the member functions on the `vkb::InstanceBuilder` object before `build()` is called.
|
||||
|
||||
The most common customization to instance creation is enabling the "Validation Layers", an invaluable tool for any vulkan application developer.
|
||||
The most common customization to instance creation is enabling the "Validation Layers", an invaluable tool for any vulkan application developer.
|
||||
```cpp
|
||||
instance_builder.request_validation_layers ();
|
||||
instance_builder.request_validation_layers();
|
||||
```
|
||||
The other common customization point is setting up the `Debug Messenger Callback`, the mechanism in which an application can control what and where the "Validation Layers" log its output.
|
||||
```cpp
|
||||
@ -34,7 +34,7 @@ instance_builder.set_debug_callback (
|
||||
[] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void *pUserData)
|
||||
void *pUserData)
|
||||
-> VkBool32 {
|
||||
auto severity = vkb::to_string_message_severity (messageSeverity);
|
||||
auto type = vkb::to_string_message_type (messageType);
|
||||
@ -49,7 +49,7 @@ instance_builder.use_default_debug_messenger();
|
||||
```
|
||||
Configuration can be chained together and done inline with building, like so.
|
||||
```cpp
|
||||
auto inst_builder_ret = instance_builder
|
||||
auto inst_builder_ret = instance_builder
|
||||
.set_app_name ("Awesome Vulkan Application")
|
||||
.set_engine_name("Excellent Game Engine")
|
||||
.require_api_version(1,0,0)
|
||||
@ -83,9 +83,9 @@ CustomVulkanWrapper custom_vk_class;
|
||||
custom_vk_class.instance = vkb_instance.instance;
|
||||
```
|
||||
|
||||
When the application is finished with the vulkan, call `vkb::destroy_instance()` to dispose of the instance and associated data.
|
||||
When the application is finished with the vulkan, call `vkb::destroy_instance()` to dispose of the instance and associated data.
|
||||
```cpp
|
||||
// cleanup
|
||||
// cleanup
|
||||
vkb::destroy_instance(vkb_instance);
|
||||
```
|
||||
### Instance Creation Summary
|
||||
@ -98,7 +98,7 @@ auto instance_builder_return = instance_builder
|
||||
.build ();
|
||||
if (!instance_builder_return) {
|
||||
// Handle error
|
||||
}
|
||||
}
|
||||
vkb::Instance vkb_instance = instance_builder_return.value ();
|
||||
|
||||
// at program end
|
||||
@ -106,11 +106,11 @@ vkb::destroy_instance(vkb_instance);
|
||||
```
|
||||
## Surface Creation
|
||||
|
||||
Presenting images to the screen Vulkan requires creating a surface, encapsulated in a `VkSurfaceKHR` handle. Creating a surface is the responsibility of the windowing system, thus is out of scope for `vk-bootstrap`. However, `vk-bootstrap` does try to make the process as painless as possible by automatically enabling the correct windowing extensions in `VkInstance` creation.
|
||||
Presenting images to the screen Vulkan requires creating a surface, encapsulated in a `VkSurfaceKHR` handle. Creating a surface is the responsibility of the windowing system, thus is out of scope for `vk-bootstrap`. However, `vk-bootstrap` does try to make the process as painless as possible by automatically enabling the correct windowing extensions in `VkInstance` creation.
|
||||
|
||||
Windowing libraries which support Vulkan usually provide a way of getting the `VkSurfaceKHR` handle for the window. These methods require a valid Vulkan instance, thus must be done after instance creation.
|
||||
|
||||
Examples for GLFW and SDL2 are listed below.
|
||||
Examples for GLFW and SDL2 are listed below.
|
||||
```cpp
|
||||
vkb::Instance vkb_instance; //valid vkb::Instance
|
||||
VkSurfaceKHR surface = nullptr;
|
||||
@ -134,7 +134,7 @@ Creating a `vkb::PhysicalDeviceSelector` requires a valid `vkb::Instance` to con
|
||||
|
||||
It follows the same pattern laid out by `vkb::InstanceBuilder`.
|
||||
```cpp
|
||||
vkb::PhysicalDeviceSelector phys_device_selector (vkb_instance);
|
||||
vkb::PhysicalDeviceSelector phys_device_selector (vkb_instance);
|
||||
auto physical_device_selector_return = phys_device_selector
|
||||
.set_surface(surface_handle)
|
||||
.select ();
|
||||
@ -149,21 +149,19 @@ By default, this will prefer a discrete GPU.
|
||||
|
||||
No cleanup is required for `vkb::PhysicalDevice`.
|
||||
|
||||
The `vkb::PhysicalDeviceSelector` will look for the first device in the list that satisfied all the specified criteria, and if none is found, will return the first device that partially satisfies the criteria.
|
||||
The `vkb::PhysicalDeviceSelector` will look for the first device in the list that satisfied all the specified criteria, and if none is found, will return the first device that partially satisfies the criteria.
|
||||
|
||||
The various "require" and "desire" pairs of functions indicate to `vk-bootstrap` what features and capabilities are necessary for an application and what are simply preferred. A "require" function will fail any `VkPhysicalDevice` that doesn't satisfy the constraint, while any criteria that doesn't satisfy the "desire" functions will make the `VkPhysicalDevice` only 'partially satisfy'.
|
||||
The various "require" functions indicate to `vk-bootstrap` what features and capabilities are necessary for an application. A "require" function will fail any `VkPhysicalDevice` that doesn't satisfy the constraint.
|
||||
|
||||
```c
|
||||
// Application cannot function without this extension
|
||||
phys_device_selector.add_required_extension("VK_KHR_timeline_semaphore");
|
||||
|
||||
// Application can deal with the lack of this extension
|
||||
phys_device_selector.add_desired_extension("VK_KHR_imageless_framebuffer");
|
||||
```
|
||||
|
||||
Note:
|
||||
Note:
|
||||
|
||||
Because `vk-bootstrap` does not manage creating a `VkSurfaceKHR` handle, it is explicitly passed into the `vkb::PhysicalDeviceSelector` for proper querying of surface support details. Unless the `vkb::InstanceBuilder::set_headless()` function was called, the physical device selector will emit `no_surface_provided` error. If an application does intend to present but cannot create a `VkSurfaceKHR` handle before physical device selection, use `defer_surface_initialization()` to disable the `no_surface_provided` error.
|
||||
Because `vk-bootstrap` does not manage creating a `VkSurfaceKHR` handle, it is explicitly passed into the `vkb::PhysicalDeviceSelector` for proper querying of surface support details. Unless the `vkb::InstanceBuilder::set_headless()` function was called, the physical device selector will emit `no_surface_provided` error. If an application does intend to present but cannot create a `VkSurfaceKHR` handle before physical device selection, use `defer_surface_initialization()` to disable the `no_surface_provided` error.
|
||||
|
||||
## Device Creation
|
||||
|
||||
@ -198,17 +196,30 @@ vkb::destroy_device(vkb_device);
|
||||
|
||||
By default, `vkb::DeviceBuilder` will enable one queue from each queue family available on the `VkPhysicalDevice`. This is done because in practice, most use cases only need a single queue from each family.
|
||||
|
||||
To get a `VkQueue` or the index of a `VkQueue`, use the `get_queue(QueueType type)` and `get_queue_index(QueueType type)` functions of `vkb::Device`. These will return the appropriate `VkQueue` or `uint32_t` if they exist and were enabled, else they will return an error.
|
||||
To get a `VkQueue` and the index of a `VkQueue`, use the `get_preferred_queue_and_index(VkQueueFlags flags)` functions of `vkb::Device`. These will return the appropriate `VkQueue` handle and `uint32_t` index stored in a `vkb::QueueAndIndex` struct if they exist and were enabled, else they will return an error.
|
||||
|
||||
```cpp
|
||||
auto queue_ret = vkb_device.get_queue (vkb::QueueType::graphics);
|
||||
auto queue_ret = vkb_device.get_preferred_queue_and_index (VK_QUEUE_GRAPHICS_BIT);
|
||||
if (!queue_ret) {
|
||||
// handle error
|
||||
}
|
||||
graphics_queue = queue_ret.value ();
|
||||
```
|
||||
|
||||
Queue families represent a set of queues with similar operations, such as graphics, transfer, and compute. Because not all Vulkan hardware has queue families for each operation category, an application should be able to handle the presence or lack of certain queue families. For this reason the `get_dedicated_queue` and `get_dedicated_queue_index` functions of `vkb::Device` exist to allow applications to easily know if there is a queue dedicated to a particular operation, such as compute or transfer operations.
|
||||
To query a queue capable of multiple operations, use multiple `VkQueueFlags` combined with bitwise-or to look for a queue that supports all specified flags, if such a queue exists.
|
||||
|
||||
```cpp
|
||||
vkb_device.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT);
|
||||
```
|
||||
|
||||
To get a `VkQueue` capable of presentation, use `get_first_presentation_queue_and_index()`.
|
||||
To check if any given queue family index is capable of presentation operations, use `queue_family_index_supports_presentation(VkQueue queue)`.
|
||||
|
||||
`get_preferred_queue_and_index(VkQueueFlags flags)` looks for a queue that supports the given queue flags while minimizing unsupported flags.
|
||||
It does not require that the queue exclusively supports only the given queue flags, which may result in the same queue handle being returns by different queries.
|
||||
Because not all Vulkan hardware has queue families for each operation category, an application needs to be careful that they didn't get the same queue handle multiple times.
|
||||
While it is fine to query the same queue multiple times, it is not fine to use that queue in multiple threads at the same time, or to ignore other synchronization requirements of VkQueue's in the Vulkan API.
|
||||
|
||||
|
||||
#### Custom queue setup
|
||||
|
||||
@ -222,14 +233,14 @@ for (uint32_t i = 0; i < static_cast<uint32_t>(queue_families.size ()); i++) {
|
||||
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
// Find the first queue family with graphics operations supported
|
||||
queue_descriptions.push_back (vkb::CustomQueueDescription (
|
||||
i, queue_families[i].queueCount,
|
||||
i, queue_families[i].queueCount,
|
||||
std::vector<float> (queue_families[i].queueCount, 1.0f)));
|
||||
}
|
||||
}
|
||||
```
|
||||
## Swapchain
|
||||
|
||||
Creating a swapchain follows the same form outlined by `vkb::InstanceBuilder` and `vkb::DeviceBuilder`. Create the `vkb::SwapchainBuilder`, provide `vkb::Device`, call the appropriate builder functions, and call `build()`.
|
||||
Creating a swapchain follows the same form outlined by `vkb::InstanceBuilder` and `vkb::DeviceBuilder`. Create the `vkb::SwapchainBuilder`, provide `vkb::Device`, call the appropriate builder functions, and call `build()`.
|
||||
|
||||
```cpp
|
||||
vkb::SwapchainBuilder swapchain_builder{ device };
|
||||
|
@ -410,6 +410,7 @@ const char* to_string(QueueError err) {
|
||||
CASE_TO_STRING(QueueError, graphics_unavailable)
|
||||
CASE_TO_STRING(QueueError, compute_unavailable)
|
||||
CASE_TO_STRING(QueueError, transfer_unavailable)
|
||||
CASE_TO_STRING(QueueError, queue_type_unavailable)
|
||||
CASE_TO_STRING(QueueError, queue_index_out_of_range)
|
||||
CASE_TO_STRING(QueueError, invalid_queue_family_index)
|
||||
default:
|
||||
@ -932,6 +933,7 @@ bool supports_features(VkPhysicalDeviceFeatures supported,
|
||||
return true;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// 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++) {
|
||||
@ -939,21 +941,33 @@ uint32_t get_first_queue_index(std::vector<VkQueueFamilyProperties> const& famil
|
||||
}
|
||||
return 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.
|
||||
|
||||
// Finds the that has the desired flag and the least number of undesired flags.
|
||||
// Any queue family with invalid_flags will be ignored.
|
||||
// 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) {
|
||||
std::vector<VkQueueFamilyProperties> const& families, VkQueueFlags desired_flags, VkQueueFlags undesired_flags, VkQueueFlags invalid_flags) {
|
||||
uint32_t index = QUEUE_INDEX_MAX_VALUE;
|
||||
uint32_t least_undesired_flags_count = QUEUE_INDEX_MAX_VALUE;
|
||||
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
|
||||
if ((families[i].queueFlags & desired_flags) == desired_flags && ((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
|
||||
if ((families[i].queueFlags & undesired_flags) == 0) {
|
||||
return i;
|
||||
} else {
|
||||
if ((invalid_flags != 0) && (families[i].queueFlags & invalid_flags) == invalid_flags) {
|
||||
continue;
|
||||
}
|
||||
if ((families[i].queueFlags & desired_flags) == desired_flags) {
|
||||
uint32_t undesired_flag_count = 0;
|
||||
// Count the number of flags which are supported by the queue family but are undesired
|
||||
for (uint32_t j = VK_QUEUE_FLAG_BITS_MAX_ENUM; j != 0; j >>= 1) {
|
||||
if (families[i].queueFlags & undesired_flags & j) {
|
||||
undesired_flag_count++;
|
||||
}
|
||||
}
|
||||
if (undesired_flag_count < least_undesired_flags_count) {
|
||||
least_undesired_flags_count = undesired_flag_count;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -961,8 +975,7 @@ uint32_t get_separate_queue_index(
|
||||
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 & desired_flags) == desired_flags &&
|
||||
(families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && (families[i].queueFlags & undesired_flags) == 0)
|
||||
if ((families[i].queueFlags & desired_flags) == desired_flags && ((families[i].queueFlags & undesired_flags) == 0))
|
||||
return i;
|
||||
}
|
||||
return QUEUE_INDEX_MAX_VALUE;
|
||||
@ -1047,13 +1060,17 @@ PhysicalDevice::Suitable PhysicalDeviceSelector::is_device_suitable(PhysicalDevi
|
||||
if (criteria.required_version > pd.properties.apiVersion) return PhysicalDevice::Suitable::no;
|
||||
if (criteria.desired_version > pd.properties.apiVersion) suitable = PhysicalDevice::Suitable::partial;
|
||||
|
||||
bool dedicated_compute = 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_queue_index(pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) !=
|
||||
detail::QUEUE_INDEX_MAX_VALUE;
|
||||
bool separate_compute = detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) !=
|
||||
bool dedicated_compute = detail::get_dedicated_queue_index(pd.queue_families,
|
||||
VK_QUEUE_COMPUTE_BIT,
|
||||
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE;
|
||||
bool dedicated_transfer = detail::get_dedicated_queue_index(pd.queue_families,
|
||||
VK_QUEUE_TRANSFER_BIT,
|
||||
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE;
|
||||
bool separate_compute = detail::get_separate_queue_index(
|
||||
pd.queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT) !=
|
||||
detail::QUEUE_INDEX_MAX_VALUE;
|
||||
bool separate_transfer = detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) !=
|
||||
bool separate_transfer = detail::get_separate_queue_index(
|
||||
pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT) !=
|
||||
detail::QUEUE_INDEX_MAX_VALUE;
|
||||
|
||||
bool present_queue = detail::get_present_queue_index(pd.physical_device, instance_info.surface, pd.queue_families) !=
|
||||
@ -1356,16 +1373,20 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::select_first_device_unconditiona
|
||||
|
||||
// PhysicalDevice
|
||||
bool PhysicalDevice::has_dedicated_compute_queue() const {
|
||||
return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE;
|
||||
return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT) !=
|
||||
detail::QUEUE_INDEX_MAX_VALUE;
|
||||
}
|
||||
bool PhysicalDevice::has_separate_compute_queue() const {
|
||||
return detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE;
|
||||
return detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT) !=
|
||||
detail::QUEUE_INDEX_MAX_VALUE;
|
||||
}
|
||||
bool PhysicalDevice::has_dedicated_transfer_queue() const {
|
||||
return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE;
|
||||
return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT) !=
|
||||
detail::QUEUE_INDEX_MAX_VALUE;
|
||||
}
|
||||
bool PhysicalDevice::has_separate_transfer_queue() const {
|
||||
return detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE;
|
||||
return detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT) !=
|
||||
detail::QUEUE_INDEX_MAX_VALUE;
|
||||
}
|
||||
std::vector<VkQueueFamilyProperties> PhysicalDevice::get_queue_families() const { return queue_families; }
|
||||
std::vector<std::string> PhysicalDevice::get_extensions() const { return extensions; }
|
||||
@ -1373,6 +1394,7 @@ PhysicalDevice::operator VkPhysicalDevice() const { return this->physical_device
|
||||
|
||||
// ---- Queues ---- //
|
||||
|
||||
// Legacy queue function
|
||||
Result<uint32_t> Device::get_queue_index(QueueType type) const {
|
||||
uint32_t index = detail::QUEUE_INDEX_MAX_VALUE;
|
||||
switch (type) {
|
||||
@ -1385,27 +1407,11 @@ Result<uint32_t> Device::get_queue_index(QueueType type) const {
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::graphics_unavailable };
|
||||
break;
|
||||
case QueueType::compute:
|
||||
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT);
|
||||
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::compute_unavailable };
|
||||
break;
|
||||
case QueueType::transfer:
|
||||
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::transfer_unavailable };
|
||||
break;
|
||||
default:
|
||||
return Result<uint32_t>{ QueueError::invalid_queue_family_index };
|
||||
}
|
||||
return index;
|
||||
}
|
||||
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_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::compute_unavailable };
|
||||
break;
|
||||
case QueueType::transfer:
|
||||
index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT);
|
||||
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::transfer_unavailable };
|
||||
break;
|
||||
default:
|
||||
@ -1414,6 +1420,25 @@ Result<uint32_t> Device::get_dedicated_queue_index(QueueType type) const {
|
||||
return index;
|
||||
}
|
||||
|
||||
// Legacy queue function
|
||||
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_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::compute_unavailable };
|
||||
break;
|
||||
case QueueType::transfer:
|
||||
index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::transfer_unavailable };
|
||||
break;
|
||||
default:
|
||||
return Result<uint32_t>{ QueueError::invalid_queue_family_index };
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// Legacy queue function
|
||||
Result<VkQueue> Device::get_queue(QueueType type) const {
|
||||
auto index = get_queue_index(type);
|
||||
if (!index.has_value()) return { index.error() };
|
||||
@ -1421,14 +1446,63 @@ Result<VkQueue> Device::get_queue(QueueType type) const {
|
||||
internal_table.fp_vkGetDeviceQueue(device, index.value(), 0, &out_queue);
|
||||
return out_queue;
|
||||
}
|
||||
|
||||
// Legacy queue function
|
||||
Result<VkQueue> Device::get_dedicated_queue(QueueType type) const {
|
||||
auto index = get_dedicated_queue_index(type);
|
||||
if (!index.has_value()) return { index.error() };
|
||||
VkQueue out_queue;
|
||||
VkQueue out_queue{};
|
||||
internal_table.fp_vkGetDeviceQueue(device, index.value(), 0, &out_queue);
|
||||
return out_queue;
|
||||
}
|
||||
|
||||
|
||||
Result<QueueAndIndex> Device::get_first_queue_and_index(VkQueueFlags queue_flags) const {
|
||||
uint32_t index = detail::get_first_queue_index(queue_families, queue_flags);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<QueueAndIndex>{ QueueError::queue_type_unavailable };
|
||||
|
||||
VkQueue out_queue{};
|
||||
internal_table.fp_vkGetDeviceQueue(device, index, 0, &out_queue);
|
||||
return QueueAndIndex{ out_queue, index };
|
||||
}
|
||||
|
||||
Result<QueueAndIndex> Device::get_preferred_queue_and_index(VkQueueFlags queue_flags) const {
|
||||
uint32_t index = detail::get_separate_queue_index(queue_families, queue_flags, ~queue_flags, 0);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<QueueAndIndex>{ QueueError::queue_type_unavailable };
|
||||
|
||||
VkQueue out_queue{};
|
||||
internal_table.fp_vkGetDeviceQueue(device, index, 0, &out_queue);
|
||||
return QueueAndIndex{ out_queue, index };
|
||||
}
|
||||
|
||||
Result<QueueAndIndex> Device::get_first_presentation_queue_and_index(VkSurfaceKHR surface_to_check) const {
|
||||
VkSurfaceKHR surface_to_use = surface;
|
||||
if (surface_to_check != VK_NULL_HANDLE) {
|
||||
surface_to_use = surface_to_check;
|
||||
}
|
||||
uint32_t index = detail::get_present_queue_index(physical_device.physical_device, surface_to_use, queue_families);
|
||||
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<QueueAndIndex>{ QueueError::present_unavailable };
|
||||
|
||||
VkQueue out_queue{};
|
||||
internal_table.fp_vkGetDeviceQueue(device, index, 0, &out_queue);
|
||||
return QueueAndIndex{ out_queue, index };
|
||||
}
|
||||
|
||||
bool Device::queue_family_index_supports_presentation(uint32_t index, VkSurfaceKHR surface_to_check) const {
|
||||
VkBool32 presentSupport = 0;
|
||||
VkSurfaceKHR surface_to_use = surface;
|
||||
if (surface_to_check != VK_NULL_HANDLE) {
|
||||
surface_to_use = surface_to_check;
|
||||
}
|
||||
if (surface_to_use != VK_NULL_HANDLE) {
|
||||
VkResult res = detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||
physical_device, index, surface_to_use, &presentSupport);
|
||||
if (res != VK_SUCCESS) return false;
|
||||
}
|
||||
return presentSupport == 1;
|
||||
}
|
||||
|
||||
|
||||
// ---- Dispatch ---- //
|
||||
|
||||
DispatchTable Device::make_table() const { return { device, fp_vkGetDeviceProcAddr }; }
|
||||
|
@ -200,6 +200,7 @@ enum class QueueError {
|
||||
graphics_unavailable,
|
||||
compute_unavailable,
|
||||
transfer_unavailable,
|
||||
queue_type_unavailable,
|
||||
queue_index_out_of_range,
|
||||
invalid_queue_family_index
|
||||
};
|
||||
@ -675,13 +676,25 @@ class PhysicalDeviceSelector {
|
||||
};
|
||||
|
||||
// ---- Queue ---- //
|
||||
enum class QueueType { present, graphics, compute, transfer };
|
||||
|
||||
enum class QueueType {
|
||||
present,
|
||||
graphics,
|
||||
compute,
|
||||
transfer,
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// Sentinel value, used in implementation only
|
||||
const uint32_t QUEUE_INDEX_MAX_VALUE = 65536;
|
||||
} // namespace detail
|
||||
|
||||
|
||||
struct QueueAndIndex {
|
||||
VkQueue queue = VK_NULL_HANDLE;
|
||||
uint32_t index = detail::QUEUE_INDEX_MAX_VALUE;
|
||||
};
|
||||
|
||||
// ---- Device ---- //
|
||||
|
||||
struct Device {
|
||||
@ -693,13 +706,34 @@ struct Device {
|
||||
PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr;
|
||||
uint32_t instance_version = VKB_VK_API_VERSION_1_0;
|
||||
|
||||
Result<uint32_t> get_queue_index(QueueType type) const;
|
||||
// Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue index
|
||||
Result<uint32_t> get_dedicated_queue_index(QueueType type) const;
|
||||
// Legacy function - gets the queue which supports queue_type operations using the following rules:
|
||||
// If queue_type is graphics, return the first queue that supports graphics operations
|
||||
// If queue_type is compute, return a queue that supports compute operations but not graphics, if one exists
|
||||
// If queue_type is transfer, return a queue that supports transfer operations but not graphics, if one exists
|
||||
// If queue_type is present, return the first queue that supports presentation with the VkSurfaceKHR given during physical device selection
|
||||
Result<uint32_t> get_queue_index(QueueType queue_type) const;
|
||||
Result<VkQueue> get_queue(QueueType queue_type) const;
|
||||
|
||||
Result<VkQueue> get_queue(QueueType type) const;
|
||||
// Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue
|
||||
Result<VkQueue> get_dedicated_queue(QueueType type) const;
|
||||
// Legacy function - gets the queue which supports only the queue_type operations using the following rules:
|
||||
// If queue_type is compute, return a queue that supports compute operations but not graphics or transfer, if one
|
||||
// exists If queue_type is transfer, return a queue that supports transfer operations but not graphics or compute,
|
||||
// if one exists If queue_type is any other type, return an error code
|
||||
Result<VkQueue> get_dedicated_queue(QueueType queue_type) const;
|
||||
Result<uint32_t> get_dedicated_queue_index(QueueType queue_type) const;
|
||||
|
||||
// Returns the first queue which supports the operations specified by queue_flags
|
||||
Result<QueueAndIndex> get_first_queue_and_index(VkQueueFlags queue_flags) const;
|
||||
|
||||
// Returns the queue which supports the operations specified by queue_flags and the least number of operations not specified by queue_flags
|
||||
Result<QueueAndIndex> get_preferred_queue_and_index(VkQueueFlags queue_flags) const;
|
||||
|
||||
// Get the first queue which supports presentation. Very unlikely to be unique.
|
||||
// If surface_to_check is not VK_NULL_HANDLE, it will make sure the surface is compatible with the queue
|
||||
// Otherwise if surface_to_check is VK_NULL_HANDLE, it will use the VkSurfaceKHR used duing physical device selection
|
||||
Result<QueueAndIndex> get_first_presentation_queue_and_index(VkSurfaceKHR surface_to_check = VK_NULL_HANDLE) const;
|
||||
|
||||
// Returns true if the given queue family index is capable of supporting presentation operations.
|
||||
bool queue_family_index_supports_presentation(uint32_t index, VkSurfaceKHR surface_to_check = VK_NULL_HANDLE) const;
|
||||
|
||||
// Return a loaded dispatch table
|
||||
DispatchTable make_table() const;
|
||||
|
@ -334,6 +334,9 @@ TEST_CASE("Swapchain", "[VkBootstrap.bootstrap]") {
|
||||
auto graphics_queue_index = device.get_queue_index(vkb::QueueType::graphics).value();
|
||||
auto present_queue_index = device.get_queue_index(vkb::QueueType::present).value();
|
||||
|
||||
REQUIRE(device.get_first_presentation_queue_and_index().has_value());
|
||||
REQUIRE(device.queue_family_index_supports_presentation(present_queue_index));
|
||||
|
||||
THEN("Swapchain can be made") {
|
||||
vkb::SwapchainBuilder swapchain_builder(device);
|
||||
auto swapchain_ret = swapchain_builder.build();
|
||||
@ -727,7 +730,7 @@ TEST_CASE("Querying Required Extension Features in 1.1", "[VkBootstrap.version]"
|
||||
}
|
||||
|
||||
TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") {
|
||||
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
|
||||
VulkanMock& mock = get_and_setup_default();
|
||||
mock.api_version = VK_API_VERSION_1_2;
|
||||
mock.physical_devices_details[0].properties.apiVersion = VK_API_VERSION_1_2;
|
||||
|
||||
@ -740,7 +743,6 @@ TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") {
|
||||
mock.physical_devices_details[0].add_features_pNext_struct(mock_vulkan_12_features);
|
||||
|
||||
GIVEN("A working instance") {
|
||||
vkb::InstanceBuilder builder;
|
||||
auto instance = get_headless_instance(2); // make sure we use 1.2
|
||||
SECTION("Requires a device that supports multiview and bufferDeviceAddress") {
|
||||
VkPhysicalDeviceVulkan11Features features_11{};
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "VkBootstrap.cpp"
|
||||
|
||||
#include "vulkan_mock.hpp"
|
||||
|
||||
TEST_CASE("Single Queue Device", "[UnitTests.queue_selection_logic]") {
|
||||
std::vector<VkQueueFamilyProperties> families = { VkQueueFamilyProperties{
|
||||
@ -9,9 +10,9 @@ TEST_CASE("Single Queue Device", "[UnitTests.queue_selection_logic]") {
|
||||
|
||||
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));
|
||||
vkb::detail::get_separate_queue_index(families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT));
|
||||
REQUIRE(vkb::detail::QUEUE_INDEX_MAX_VALUE ==
|
||||
vkb::detail::get_separate_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT));
|
||||
vkb::detail::get_separate_queue_index(families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_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 ==
|
||||
@ -22,14 +23,16 @@ TEST_CASE("Dedicated Compute Queue, Separate Transfer", "[UnitTests.queue_select
|
||||
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 } },
|
||||
VK_QUEUE_GRAPHICS_BIT | 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 } },
|
||||
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_separate_queue_index(
|
||||
families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT, 0));
|
||||
REQUIRE(2 == vkb::detail::get_separate_queue_index(
|
||||
families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0));
|
||||
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));
|
||||
@ -37,14 +40,16 @@ TEST_CASE("Dedicated Compute Queue, Separate Transfer", "[UnitTests.queue_select
|
||||
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 } },
|
||||
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | 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 } },
|
||||
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_separate_queue_index(
|
||||
families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT, 0));
|
||||
REQUIRE(1 == vkb::detail::get_separate_queue_index(
|
||||
families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0));
|
||||
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));
|
||||
@ -55,14 +60,16 @@ TEST_CASE("Dedicated Transfer Queue, Separate Compute", "[UnitTests.queue_select
|
||||
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 } },
|
||||
VK_QUEUE_GRAPHICS_BIT | 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 } },
|
||||
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(2 == vkb::detail::get_separate_queue_index(
|
||||
families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT, 0));
|
||||
REQUIRE(1 == vkb::detail::get_separate_queue_index(
|
||||
families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0));
|
||||
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));
|
||||
@ -70,16 +77,208 @@ TEST_CASE("Dedicated Transfer Queue, Separate Compute", "[UnitTests.queue_select
|
||||
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 } },
|
||||
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | 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 } },
|
||||
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(1 == vkb::detail::get_separate_queue_index(
|
||||
families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT, 0));
|
||||
REQUIRE(2 == vkb::detail::get_separate_queue_index(
|
||||
families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
vkb::Device setup_mock_for_queue_selection(std::vector<VkQueueFamilyProperties> const& queue_families) {
|
||||
VulkanMock& mock = get_vulkan_mock();
|
||||
VulkanMock::PhysicalDeviceDetails physical_device_details{};
|
||||
physical_device_details.properties.apiVersion = VK_API_VERSION_1_0;
|
||||
physical_device_details.queue_family_properties = queue_families;
|
||||
mock.add_physical_device(std::move(physical_device_details));
|
||||
|
||||
return vkb::DeviceBuilder{
|
||||
vkb::PhysicalDeviceSelector{ vkb::InstanceBuilder{}.set_headless().build().value() }.select().value()
|
||||
}
|
||||
.build()
|
||||
.value();
|
||||
}
|
||||
|
||||
TEST_CASE("Single Uber Queue", "[UnitTests.get_first_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_first_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_first_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 0 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_first_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 0 && q2.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q3 =
|
||||
d.get_first_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q3.index == 0 && q3.queue != nullptr));
|
||||
|
||||
CHECK(d.get_first_queue_and_index(VK_QUEUE_PROTECTED_BIT).matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
CHECK(d.get_first_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT)
|
||||
.matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
}
|
||||
|
||||
TEST_CASE("Uber, Compute + Transfer", "[UnitTests.get_first_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_first_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_first_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 0 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_first_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 0 && q2.queue != nullptr));
|
||||
}
|
||||
|
||||
TEST_CASE("Single Uber Queue", "[UnitTests.get_preferred_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_preferred_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 0 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_preferred_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 0 && q2.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q3 =
|
||||
d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q3.index == 0 && q3.queue != nullptr));
|
||||
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_PROTECTED_BIT).matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
}
|
||||
|
||||
TEST_CASE("Uber, Compute + Transfer", "[UnitTests.get_preferred_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_preferred_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 1 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_preferred_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 1 && q2.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q3 =
|
||||
d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q3.index == 0 && q3.queue != nullptr));
|
||||
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_PROTECTED_BIT).matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT)
|
||||
.matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
}
|
||||
|
||||
TEST_CASE("Uber, Compute + Transfer, Compute", "[UnitTests.get_preferred_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_preferred_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 2 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_preferred_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 1 && q2.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q3 =
|
||||
d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q3.index == 0 && q3.queue != nullptr));
|
||||
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_PROTECTED_BIT).matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT)
|
||||
.matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
}
|
||||
|
||||
TEST_CASE("Uber, Compute, Compute + Transfer", "[UnitTests.get_preferred_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_preferred_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 1 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_preferred_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 2 && q2.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q3 =
|
||||
d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q3.index == 0 && q3.queue != nullptr));
|
||||
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_PROTECTED_BIT).matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT)
|
||||
.matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
}
|
||||
|
||||
TEST_CASE("Uber, Transfer, Compute + Transfer", "[UnitTests.get_preferred_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_preferred_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 2 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_preferred_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 1 && q2.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q3 =
|
||||
d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q3.index == 0 && q3.queue != nullptr));
|
||||
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_PROTECTED_BIT).matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT)
|
||||
.matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
}
|
||||
|
||||
TEST_CASE("Uber, Compute + Transfer, Transfer", "[UnitTests.get_preferred_queue_and_index]") {
|
||||
vkb::Device d = setup_mock_for_queue_selection(
|
||||
{ VkQueueFamilyProperties{ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
|
||||
VkQueueFamilyProperties{ VK_QUEUE_TRANSFER_BIT, 1 } });
|
||||
|
||||
vkb::QueueAndIndex q0 = d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT).value();
|
||||
CHECK((q0.index == 0 && q0.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q1 = d.get_preferred_queue_and_index(VK_QUEUE_COMPUTE_BIT).value();
|
||||
CHECK((q1.index == 1 && q1.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q2 = d.get_preferred_queue_and_index(VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q2.index == 2 && q2.queue != nullptr));
|
||||
|
||||
vkb::QueueAndIndex q3 =
|
||||
d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT).value();
|
||||
CHECK((q3.index == 0 && q3.queue != nullptr));
|
||||
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_PROTECTED_BIT).matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
CHECK(d.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT)
|
||||
.matches_error(vkb::QueueError::queue_type_unavailable));
|
||||
}
|
||||
|
@ -296,7 +296,9 @@ VKAPI_ATTR VkResult VKAPI_CALL shim_vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (surface && pSupported) *pSupported = true;
|
||||
if (surface && pSupported) {
|
||||
*pSupported = true;
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
VKAPI_ATTR VkResult VKAPI_CALL shim_vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||
|
Loading…
Reference in New Issue
Block a user