Skip to content

Commit f290028

Browse files
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
1 parent be0df09 commit f290028

File tree

6 files changed

+396
-74
lines changed

6 files changed

+396
-74
lines changed

docs/getting_started.md

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Getting Started
22

3-
`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.
3+
`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.
44

55
## Instance Creation
66

@@ -16,25 +16,25 @@ Because creating an instance may fail, the builder returns an 'Result' type. Thi
1616
if (!instance_builder_return) {
1717
std::cerr << "Failed to create Vulkan instance. Error: " << instance_builder_return.error().message() << "\n";
1818
return -1;
19-
}
19+
}
2020
```
21-
Once any possible errors have been dealt with, we can pull the `vkb::Instance` struct out of the `Result`.
21+
Once any possible errors have been dealt with, we can pull the `vkb::Instance` struct out of the `Result`.
2222
```cpp
2323
vkb::Instance vkb_instance = instance_builder_return.value();
2424
```
2525
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.
2626

27-
The most common customization to instance creation is enabling the "Validation Layers", an invaluable tool for any vulkan application developer.
27+
The most common customization to instance creation is enabling the "Validation Layers", an invaluable tool for any vulkan application developer.
2828
```cpp
29-
instance_builder.request_validation_layers ();
29+
instance_builder.request_validation_layers();
3030
```
3131
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.
3232
```cpp
3333
instance_builder.set_debug_callback (
3434
[] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
3535
VkDebugUtilsMessageTypeFlagsEXT messageType,
3636
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
37-
void *pUserData)
37+
void *pUserData)
3838
-> VkBool32 {
3939
auto severity = vkb::to_string_message_severity (messageSeverity);
4040
auto type = vkb::to_string_message_type (messageType);
@@ -49,7 +49,7 @@ instance_builder.use_default_debug_messenger();
4949
```
5050
Configuration can be chained together and done inline with building, like so.
5151
```cpp
52-
auto inst_builder_ret = instance_builder
52+
auto inst_builder_ret = instance_builder
5353
.set_app_name ("Awesome Vulkan Application")
5454
.set_engine_name("Excellent Game Engine")
5555
.require_api_version(1,0,0)
@@ -83,9 +83,9 @@ CustomVulkanWrapper custom_vk_class;
8383
custom_vk_class.instance = vkb_instance.instance;
8484
```
8585
86-
When the application is finished with the vulkan, call `vkb::destroy_instance()` to dispose of the instance and associated data.
86+
When the application is finished with the vulkan, call `vkb::destroy_instance()` to dispose of the instance and associated data.
8787
```cpp
88-
// cleanup
88+
// cleanup
8989
vkb::destroy_instance(vkb_instance);
9090
```
9191
### Instance Creation Summary
@@ -98,19 +98,19 @@ auto instance_builder_return = instance_builder
9898
.build ();
9999
if (!instance_builder_return) {
100100
// Handle error
101-
}
101+
}
102102
vkb::Instance vkb_instance = instance_builder_return.value ();
103103

104104
// at program end
105105
vkb::destroy_instance(vkb_instance);
106106
```
107107
## Surface Creation
108108
109-
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.
109+
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.
110110
111111
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.
112112
113-
Examples for GLFW and SDL2 are listed below.
113+
Examples for GLFW and SDL2 are listed below.
114114
```cpp
115115
vkb::Instance vkb_instance; //valid vkb::Instance
116116
VkSurfaceKHR surface = nullptr;
@@ -134,7 +134,7 @@ Creating a `vkb::PhysicalDeviceSelector` requires a valid `vkb::Instance` to con
134134

135135
It follows the same pattern laid out by `vkb::InstanceBuilder`.
136136
```cpp
137-
vkb::PhysicalDeviceSelector phys_device_selector (vkb_instance);
137+
vkb::PhysicalDeviceSelector phys_device_selector (vkb_instance);
138138
auto physical_device_selector_return = phys_device_selector
139139
.set_surface(surface_handle)
140140
.select ();
@@ -149,21 +149,19 @@ By default, this will prefer a discrete GPU.
149149
150150
No cleanup is required for `vkb::PhysicalDevice`.
151151
152-
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.
152+
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.
153153
154-
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'.
154+
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.
155155
156156
```c
157157
// Application cannot function without this extension
158158
phys_device_selector.add_required_extension("VK_KHR_timeline_semaphore");
159159
160-
// Application can deal with the lack of this extension
161-
phys_device_selector.add_desired_extension("VK_KHR_imageless_framebuffer");
162160
```
163161

164-
Note:
162+
Note:
165163

166-
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.
164+
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.
167165

168166
## Device Creation
169167

@@ -198,17 +196,30 @@ vkb::destroy_device(vkb_device);
198196
199197
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.
200198
201-
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.
199+
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.
202200
203201
```cpp
204-
auto queue_ret = vkb_device.get_queue (vkb::QueueType::graphics);
202+
auto queue_ret = vkb_device.get_preferred_queue_and_index (VK_QUEUE_GRAPHICS_BIT);
205203
if (!queue_ret) {
206204
// handle error
207205
}
208206
graphics_queue = queue_ret.value ();
209207
```
210208

211-
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.
209+
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.
210+
211+
```cpp
212+
vkb_device.get_preferred_queue_and_index(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT);
213+
```
214+
215+
To get a `VkQueue` capable of presentation, use `get_first_presentation_queue_and_index()`.
216+
To check if any given queue family index is capable of presentation operations, use `queue_family_index_supports_presentation(VkQueue queue)`.
217+
218+
`get_preferred_queue_and_index(VkQueueFlags flags)` looks for a queue that supports the given queue flags while minimizing unsupported flags.
219+
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.
220+
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.
221+
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.
222+
212223

213224
#### Custom queue setup
214225

@@ -222,14 +233,14 @@ for (uint32_t i = 0; i < static_cast<uint32_t>(queue_families.size ()); i++) {
222233
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
223234
// Find the first queue family with graphics operations supported
224235
queue_descriptions.push_back (vkb::CustomQueueDescription (
225-
i, queue_families[i].queueCount,
236+
i, queue_families[i].queueCount,
226237
std::vector<float> (queue_families[i].queueCount, 1.0f)));
227238
}
228239
}
229240
```
230241
## Swapchain
231242

232-
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()`.
243+
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()`.
233244

234245
```cpp
235246
vkb::SwapchainBuilder swapchain_builder{ device };

0 commit comments

Comments
 (0)