mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-22 15:24:34 +00:00
Update getting_started.md
Include reference to add_required_extension_features and per-version feature enables. Fix type with CustomQueueDescription.
This commit is contained in:
parent
a330227666
commit
3849dafadb
@ -1,6 +1,6 @@
|
|||||||
# Getting Started
|
# 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
|
## Instance Creation
|
||||||
|
|
||||||
@ -16,15 +16,15 @@ Because creating an instance may fail, the builder returns an 'Result' type. Thi
|
|||||||
if (!instance_builder_return) {
|
if (!instance_builder_return) {
|
||||||
std::cerr << "Failed to create Vulkan instance. Error: " << instance_builder_return.error().message() << "\n";
|
std::cerr << "Failed to create Vulkan instance. Error: " << instance_builder_return.error().message() << "\n";
|
||||||
return -1;
|
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
|
```cpp
|
||||||
vkb::Instance vkb_instance = instance_builder_return.value();
|
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.
|
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
|
```cpp
|
||||||
instance_builder.request_validation_layers ();
|
instance_builder.request_validation_layers ();
|
||||||
```
|
```
|
||||||
@ -34,7 +34,7 @@ instance_builder.set_debug_callback (
|
|||||||
[] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
[] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
void *pUserData)
|
void *pUserData)
|
||||||
-> VkBool32 {
|
-> VkBool32 {
|
||||||
auto severity = vkb::to_string_message_severity (messageSeverity);
|
auto severity = vkb::to_string_message_severity (messageSeverity);
|
||||||
auto type = vkb::to_string_message_type (messageType);
|
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.
|
Configuration can be chained together and done inline with building, like so.
|
||||||
```cpp
|
```cpp
|
||||||
auto inst_builder_ret = instance_builder
|
auto inst_builder_ret = instance_builder
|
||||||
.set_app_name ("Awesome Vulkan Application")
|
.set_app_name ("Awesome Vulkan Application")
|
||||||
.set_engine_name("Excellent Game Engine")
|
.set_engine_name("Excellent Game Engine")
|
||||||
.require_api_version(1,0,0)
|
.require_api_version(1,0,0)
|
||||||
@ -83,9 +83,9 @@ CustomVulkanWrapper custom_vk_class;
|
|||||||
custom_vk_class.instance = vkb_instance.instance;
|
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
|
```cpp
|
||||||
// cleanup
|
// cleanup
|
||||||
vkb::destroy_instance(vkb_instance);
|
vkb::destroy_instance(vkb_instance);
|
||||||
```
|
```
|
||||||
### Instance Creation Summary
|
### Instance Creation Summary
|
||||||
@ -98,7 +98,7 @@ auto instance_builder_return = instance_builder
|
|||||||
.build ();
|
.build ();
|
||||||
if (!instance_builder_return) {
|
if (!instance_builder_return) {
|
||||||
// Handle error
|
// Handle error
|
||||||
}
|
}
|
||||||
vkb::Instance vkb_instance = instance_builder_return.value ();
|
vkb::Instance vkb_instance = instance_builder_return.value ();
|
||||||
|
|
||||||
// at program end
|
// at program end
|
||||||
@ -106,11 +106,11 @@ vkb::destroy_instance(vkb_instance);
|
|||||||
```
|
```
|
||||||
## Surface Creation
|
## 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.
|
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
|
```cpp
|
||||||
vkb::Instance vkb_instance; //valid vkb::Instance
|
vkb::Instance vkb_instance; //valid vkb::Instance
|
||||||
VkSurfaceKHR surface = nullptr;
|
VkSurfaceKHR surface = nullptr;
|
||||||
@ -134,14 +134,14 @@ Creating a `vkb::PhysicalDeviceSelector` requires a valid `vkb::Instance` to con
|
|||||||
|
|
||||||
It follows the same pattern laid out by `vkb::InstanceBuilder`.
|
It follows the same pattern laid out by `vkb::InstanceBuilder`.
|
||||||
```cpp
|
```cpp
|
||||||
vkb::PhysicalDeviceSelector phys_device_selector (vkb_instance);
|
vkb::PhysicalDeviceSelector phys_device_selector (vkb_instance);
|
||||||
auto physical_device_selector_return = phys_device_selector
|
auto physical_device_selector_return = phys_device_selector
|
||||||
.set_surface(surface_handle)
|
.set_surface(surface_handle)
|
||||||
.select ();
|
.select ();
|
||||||
if (!physical_device_selector_return) {
|
if (!physical_device_selector_return) {
|
||||||
// Handle error
|
// Handle error
|
||||||
}
|
}
|
||||||
auto phys_device = phys_device_ret.value ();
|
auto phys_device = physical_device_selector_return.value ();
|
||||||
```
|
```
|
||||||
|
|
||||||
To select a physical device, call `select()` on the `vkb::PhysicalDeviceSelector` object.
|
To select a physical device, call `select()` on the `vkb::PhysicalDeviceSelector` object.
|
||||||
@ -149,11 +149,13 @@ By default, this will prefer a discrete GPU.
|
|||||||
|
|
||||||
No cleanup is required for `vkb::PhysicalDevice`.
|
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
|
For example, "requiring" certain device extensions to be supported is done as follows:
|
||||||
|
|
||||||
|
```cpp
|
||||||
// Application cannot function without this extension
|
// Application cannot function without this extension
|
||||||
phys_device_selector.add_required_extension("VK_KHR_timeline_semaphore");
|
phys_device_selector.add_required_extension("VK_KHR_timeline_semaphore");
|
||||||
|
|
||||||
@ -161,9 +163,50 @@ phys_device_selector.add_required_extension("VK_KHR_timeline_semaphore");
|
|||||||
phys_device_selector.add_desired_extension("VK_KHR_imageless_framebuffer");
|
phys_device_selector.add_desired_extension("VK_KHR_imageless_framebuffer");
|
||||||
```
|
```
|
||||||
|
|
||||||
Note:
|
While requiring that certain features are available is as follows:
|
||||||
|
|
||||||
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.
|
```cpp
|
||||||
|
VkPhysicalDeviceFeatures required_features{};
|
||||||
|
required_features.multiViewport = true;
|
||||||
|
|
||||||
|
phys_device_selector.set_required_features(required_features);
|
||||||
|
```
|
||||||
|
|
||||||
|
To enable features for newer versions of Vulkan, use `set_required_features_11()`, `set_required_features_12()`, and `set_required_features_13()` and follow the same pattern as `set_required_features()` of passing in the features struct, corresponding to the version.
|
||||||
|
|
||||||
|
Note that `set_required_features_11()` was released with 1.2, so it cannot be used for 1.1 only capable Vulkan devices.
|
||||||
|
|
||||||
|
Features only available through extensions need to use `add_required_extension_features()`. For example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features{};
|
||||||
|
descriptor_indexing_features.<features_used> = true;
|
||||||
|
|
||||||
|
phys_device_selector.add_required_extension_features(&descriptor_indexing_features);
|
||||||
|
```
|
||||||
|
|
||||||
|
The features and extensions used as selection criteria in `vkb::PhysicalDeviceSelector` automatically propagate into `vkb::DeviceBuilder`. That means the application only needs to state the feature requirement once, and `vk-bootstrap` will handle enabling it on the resulting device.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Physical Device
|
||||||
|
|
||||||
|
The `vkb::PhysicalDevice` represents a chosen physical device, along with all the necessary details about how to create a `VkDevice` from it with the requested features and extensions. While most use cases will simply give the `vkb::PhysicalDevice` to `vkb::DeviceBuilder`, there are a handful of useful things that can be done with it.
|
||||||
|
|
||||||
|
Adding optional extensions. It is occasionally useful to enable features if they are present but not require that they be available on the physical device.
|
||||||
|
|
||||||
|
This is done using `enable_extension_if_present()` as follows.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool supported = phys_device.enable_extension_if_present("VK_KHR_timeline_semaphore");
|
||||||
|
if (supported){
|
||||||
|
// allows easy feedback whether an extension is supported or not.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `enable_extensions_if_present()` to check if a group of extensions are available, and enable all of them if they are all present. This will *not* enable any extension unless they are all present, useful for handling dependencies between extensions, where one extension requires another one to be enabled.
|
||||||
|
|
||||||
## Device Creation
|
## Device Creation
|
||||||
|
|
||||||
@ -178,17 +221,6 @@ if (!dev_ret) {
|
|||||||
vkb::Device vkb_device = dev_ret.value();
|
vkb::Device vkb_device = dev_ret.value();
|
||||||
```
|
```
|
||||||
|
|
||||||
The features and extensions used as selection criteria in `vkb::PhysicalDeviceSelector` automatically propagate into `vkb::DeviceBuilder`. Because of this, there is no way to enable features or extensions that were not specified during `vkb::PhysicalDeviceSelector`. This is by design as any feature or extension enabled in a device *must* have support from the `VkPhysicalDevice` it is created with.
|
|
||||||
|
|
||||||
The common method to extend Vulkan functionality in existing API calls is to use the pNext chain. This is accounted for `VkDevice` creation with the `add_pNext` member function of `vkb::DeviceBuilder`. Note: Any structures added to the pNext chain must remain valid until `build()` is called.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features{};
|
|
||||||
|
|
||||||
auto dev_ret = device_builder.add_pNext(&descriptor_indexing_features)
|
|
||||||
.build ();
|
|
||||||
```
|
|
||||||
|
|
||||||
To destroy a `vkb::Device`, call `vkb::destroy_device()`.
|
To destroy a `vkb::Device`, call `vkb::destroy_device()`.
|
||||||
```cpp
|
```cpp
|
||||||
vkb::destroy_device(vkb_device);
|
vkb::destroy_device(vkb_device);
|
||||||
@ -222,14 +254,13 @@ for (uint32_t i = 0; i < static_cast<uint32_t>(queue_families.size ()); i++) {
|
|||||||
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||||
// Find the first queue family with graphics operations supported
|
// Find the first queue family with graphics operations supported
|
||||||
queue_descriptions.push_back (vkb::CustomQueueDescription (
|
queue_descriptions.push_back (vkb::CustomQueueDescription (
|
||||||
i, queue_families[i].queueCount,
|
|
||||||
std::vector<float> (queue_families[i].queueCount, 1.0f)));
|
std::vector<float> (queue_families[i].queueCount, 1.0f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
## Swapchain
|
## 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
|
```cpp
|
||||||
vkb::SwapchainBuilder swapchain_builder{ device };
|
vkb::SwapchainBuilder swapchain_builder{ device };
|
||||||
|
Loading…
Reference in New Issue
Block a user