Make Vulkan 1.1 Headers required

Previously, the code tried to make it possible to use vk-bootstrap with
Vulkan 1.0 headers. This makes the code complicated and left several paths
completly untested. Making Vulkan 1.1 headers allows for simpler code.

Note: This does NOT make a Vulkan 1.1 capable driver required to use
vk-bootstrap. This only requires that the headers used to build
vk-bootstrap are 1.1 or above.
This commit is contained in:
Charles Giessen 2023-01-12 15:33:10 -07:00 committed by Charles Giessen
parent 932b7794ac
commit 8e61b2d81c
3 changed files with 30 additions and 55 deletions

View File

@ -1,6 +1,6 @@
# `vk-bootstrap` # `vk-bootstrap`
A utility library that jump starts initialization of Vulkan A utility library that jump starts initialization of Vulkan
This library simplifies the tedious process of: This library simplifies the tedious process of:
@ -76,19 +76,19 @@ See `example/triangle.cpp` for an example that renders a triangle to the screen.
## Setting up `vk-bootstrap` ## Setting up `vk-bootstrap`
This library has no external dependencies beyond C++14, its standard library, and the Vulkan Headers. This library has no external dependencies beyond C++14, its standard library, and at least the 1.1 version of the Vulkan Headers.
Note: on Unix platforms, `vk-bootstrap` will require the dynamic linker in order to compile as the library doesn't link against `vulkan-1.dll`/`libvulkan.so` directly. Note: on Unix platforms, `vk-bootstrap` will require the dynamic linker in order to compile as the library doesn't link against `vulkan-1.dll`/`libvulkan.so` directly.
### Copy-Paste ### Copy-Paste
Copy the `src/VkBootstrap.h` and `src/VkBootstrap.cpp` files into your project, include them into your build, then compile as you normally would. Copy the `src/VkBootstrap.h`, `src/VkBootstrapDispatch.h`, and `src/VkBootstrap.cpp` files into your project, include them into your build, then compile as you normally would.
`vk-bootstrap` is *not* a header only library, so no need to worry about macros in the header. `vk-bootstrap` is *not* a header only library, so no need to worry about macros in the header.
#### Linux specific #### Linux specific
vk-bootstrap will load the required symbols at runtime, which requires that the application is linked to the system dynamic link. vk-bootstrap will load the required symbols at runtime, which requires that the application is linked to the system dynamic link.
How the dynamic linker is linked into the project depends on the build system in question. How the dynamic linker is linked into the project depends on the build system in question.
If CMake is being used, link vk-bootstrap with `${CMAKE_DL_LIBS}`. If CMake is being used, link vk-bootstrap with `${CMAKE_DL_LIBS}`.
@ -106,7 +106,7 @@ With CMake, add the subdirectory to include the project
add_subdirectory(vk-bootstrap) add_subdirectory(vk-bootstrap)
``` ```
Then use `target_link_libraries` to use the library in whichever target needs it. Then use `target_link_libraries` to use the library in whichever target needs it.
```cmake ```cmake
target_link_libraries(your_application_name vk-bootstrap::vk-bootstrap) target_link_libraries(your_application_name vk-bootstrap::vk-bootstrap)
@ -120,7 +120,7 @@ include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
fetch_vk_bootstrap fetch_vk_bootstrap
GIT_REPOSITORY https://github.com/charles-lunarg/vk-bootstrap GIT_REPOSITORY https://github.com/charles-lunarg/vk-bootstrap
GIT_TAG BRANCH_OR_TAG #suggest using a tag so the library doesn't update whenever new commits are pushed to a branch GIT_TAG BRANCH_OR_TAG #suggest using a tag so the library doesn't update whenever new commits are pushed to a branch
) )
FetchContent_MakeAvailable(fetch_vk_bootstrap) FetchContent_MakeAvailable(fetch_vk_bootstrap)
target_link_libraries(your_application_name vk-bootstrap::vk-bootstrap) target_link_libraries(your_application_name vk-bootstrap::vk-bootstrap)
@ -151,7 +151,7 @@ cmake ../path/to/your_project/ -DVK_BOOTSTRAP_TEST=ON
### Build Options ### Build Options
| Name | Type | Default Value | Description | | Name | Type | Default Value | Description |
| ---- | --- | ---- | ----- | | ---- | --- | ---- | ----- |
| `VK_BOOTSTRAP_WERROR` | bool | `OFF` | Enable warnings as errors during compilation. | | `VK_BOOTSTRAP_WERROR` | bool | `OFF` | Enable warnings as errors during compilation. |
| `VK_BOOTSTRAP_TEST` | bool | `OFF` | Enable building of the tests in this project. Will download GLFW and Catch2 automatically if enabled. | | `VK_BOOTSTRAP_TEST` | bool | `OFF` | Enable building of the tests in this project. Will download GLFW and Catch2 automatically if enabled. |
| `VK_BOOTSTRAP_VULKAN_HEADER_DIR` | string | `""` | Optional. Specify the directory that contains the Vulkan Headers. Useful if you are downloading the headers manually and don't want vk-bootstrap to download them itself. | | `VK_BOOTSTRAP_VULKAN_HEADER_DIR` | string | `""` | Optional. Specify the directory that contains the Vulkan Headers. Useful if you are downloading the headers manually and don't want vk-bootstrap to download them itself. |

View File

@ -587,11 +587,11 @@ Result<Instance> InstanceBuilder::build() const {
if (info.debug_callback != nullptr && system.debug_utils_available) { if (info.debug_callback != nullptr && system.debug_utils_available) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
} }
bool properties2_ext_enabled = false; bool properties2_ext_enabled =
if (detail::check_extension_supported(system.available_extensions, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) && api_version < VKB_VK_API_VERSION_1_1 && detail::check_extension_supported(system.available_extensions,
api_version < VKB_VK_API_VERSION_1_1) { VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
if (properties2_ext_enabled) {
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
properties2_ext_enabled = true;
} }
#if defined(VK_KHR_portability_enumeration) #if defined(VK_KHR_portability_enumeration)
@ -1010,14 +1010,14 @@ PhysicalDevice PhysicalDeviceSelector::populate_device_details(VkPhysicalDevice
for (const auto& ext : available_extensions) { for (const auto& ext : available_extensions) {
physical_device.extensions.push_back(&ext.extensionName[0]); physical_device.extensions.push_back(&ext.extensionName[0]);
} }
#if defined(VK_KHR_get_physical_device_properties2)
physical_device.features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; // same value as the non-KHR version physical_device.features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; // same value as the non-KHR version
#endif
physical_device.properties2_ext_enabled = instance_info.properties2_ext_enabled; physical_device.properties2_ext_enabled = instance_info.properties2_ext_enabled;
auto fill_chain = src_extended_features_chain; auto fill_chain = src_extended_features_chain;
if (!fill_chain.empty() && (instance_info.version >= VKB_VK_API_VERSION_1_1 || instance_info.properties2_ext_enabled)) { bool instance_is_1_1 = instance_info.version >= VKB_VK_API_VERSION_1_1;
if (!fill_chain.empty() && (instance_is_1_1 || instance_info.properties2_ext_enabled)) {
detail::GenericFeaturesPNextNode* prev = nullptr; detail::GenericFeaturesPNextNode* prev = nullptr;
for (auto& extension : fill_chain) { for (auto& extension : fill_chain) {
@ -1027,29 +1027,15 @@ PhysicalDevice PhysicalDeviceSelector::populate_device_details(VkPhysicalDevice
prev = &extension; prev = &extension;
} }
bool phys_dev_is_1_1 = instance_info.version >= VKB_VK_API_VERSION_1_1 && VkPhysicalDeviceFeatures2 local_features{};
physical_device.properties.apiVersion >= VKB_VK_API_VERSION_1_1; local_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; // KHR is same as core here
local_features.pNext = &fill_chain.front();
#if defined(VKB_VK_API_VERSION_1_1) // Use KHR function if not able to use the core function
if (phys_dev_is_1_1 || instance_info.properties2_ext_enabled) { if (instance_is_1_1) {
VkPhysicalDeviceFeatures2 local_features{}; detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(vk_phys_device, &local_features);
local_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; // KHR is same as core here } else {
local_features.pNext = &fill_chain.front(); detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2KHR(vk_phys_device, &local_features);
// Use KHR function if not able to use the core function
if (!phys_dev_is_1_1) {
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2KHR(vk_phys_device, &local_features);
} else {
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(vk_phys_device, &local_features);
}
} }
#elif defined(VK_KHR_get_physical_device_properties2)
if (instance_info.properties2_ext_enabled) {
VkPhysicalDeviceFeatures2KHR local_features_khr{};
local_features_khr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
local_features_khr.pNext = &fill_chain.front();
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2KHR(vk_phys_device, &local_features_khr);
}
#endif
physical_device.extended_features_chain = fill_chain; physical_device.extended_features_chain = fill_chain;
} }
@ -1496,7 +1482,6 @@ Result<Device> DeviceBuilder::build() const {
std::vector<VkBaseOutStructure*> final_pnext_chain; std::vector<VkBaseOutStructure*> final_pnext_chain;
VkDeviceCreateInfo device_create_info = {}; VkDeviceCreateInfo device_create_info = {};
#if defined(VK_KHR_get_physical_device_properties2)
bool user_defined_phys_dev_features_2 = false; bool user_defined_phys_dev_features_2 = false;
for (auto& pnext : info.pNext_chain) { for (auto& pnext : info.pNext_chain) {
if (pnext->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) { if (pnext->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) {
@ -1526,7 +1511,6 @@ Result<Device> DeviceBuilder::build() const {
device_create_info.pEnabledFeatures = &physical_device.features; device_create_info.pEnabledFeatures = &physical_device.features;
} }
} }
#endif
for (auto& pnext : info.pNext_chain) { for (auto& pnext : info.pNext_chain) {
final_pnext_chain.push_back(pnext); final_pnext_chain.push_back(pnext);
@ -1877,7 +1861,6 @@ Result<std::vector<VkImageView>> Swapchain::get_image_views(const void* pNext) {
if (!swapchain_images_ret) return swapchain_images_ret.error(); if (!swapchain_images_ret) return swapchain_images_ret.error();
const auto swapchain_images = swapchain_images_ret.value(); const auto swapchain_images = swapchain_images_ret.value();
#if defined(VK_VERSION_1_1)
bool already_contains_image_view_usage = false; bool already_contains_image_view_usage = false;
while (pNext) { while (pNext) {
if (reinterpret_cast<const VkBaseInStructure*>(pNext)->sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO) { if (reinterpret_cast<const VkBaseInStructure*>(pNext)->sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO) {
@ -1890,20 +1873,17 @@ Result<std::vector<VkImageView>> Swapchain::get_image_views(const void* pNext) {
desired_flags.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; desired_flags.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
desired_flags.pNext = pNext; desired_flags.pNext = pNext;
desired_flags.usage = image_usage_flags; desired_flags.usage = image_usage_flags;
#endif
std::vector<VkImageView> views(swapchain_images.size()); std::vector<VkImageView> views(swapchain_images.size());
for (size_t i = 0; i < swapchain_images.size(); i++) { for (size_t i = 0; i < swapchain_images.size(); i++) {
VkImageViewCreateInfo createInfo = {}; VkImageViewCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
#if defined(VK_VERSION_1_1)
if (instance_version >= VKB_VK_API_VERSION_1_1 && !already_contains_image_view_usage) { if (instance_version >= VKB_VK_API_VERSION_1_1 && !already_contains_image_view_usage) {
createInfo.pNext = &desired_flags; createInfo.pNext = &desired_flags;
} else { } else {
createInfo.pNext = pNext; createInfo.pNext = pNext;
} }
#else
createInfo.pNext = pNext;
#endif
createInfo.image = swapchain_images[i]; createInfo.image = swapchain_images[i];
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.format = image_format; createInfo.format = image_format;

View File

@ -501,11 +501,8 @@ struct PhysicalDevice {
std::vector<std::string> extensions; std::vector<std::string> extensions;
std::vector<VkQueueFamilyProperties> queue_families; std::vector<VkQueueFamilyProperties> queue_families;
std::vector<detail::GenericFeaturesPNextNode> extended_features_chain; std::vector<detail::GenericFeaturesPNextNode> extended_features_chain;
#if defined(VKB_VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 features2{}; VkPhysicalDeviceFeatures2 features2{};
#else
VkPhysicalDeviceFeatures2KHR features2{};
#endif
bool defer_surface_initialization = false; bool defer_surface_initialization = false;
bool properties2_ext_enabled = false; bool properties2_ext_enabled = false;
enum class Suitable { yes, partial, no }; enum class Suitable { yes, partial, no };
@ -598,12 +595,11 @@ class PhysicalDeviceSelector {
// Require a physical device which supports a specific set of general/extension features. // Require a physical device which supports a specific set of general/extension features.
// If this function is used, the user should not put their own VkPhysicalDeviceFeatures2 in // If this function is used, the user should not put their own VkPhysicalDeviceFeatures2 in
// the pNext chain of VkDeviceCreateInfo. // the pNext chain of VkDeviceCreateInfo.
#if defined(VKB_VK_API_VERSION_1_1)
template <typename T> PhysicalDeviceSelector& add_required_extension_features(T const& features) { template <typename T> PhysicalDeviceSelector& add_required_extension_features(T const& features) {
criteria.extended_features_chain.push_back(features); criteria.extended_features_chain.push_back(features);
return *this; return *this;
} }
#endif
// 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 const& features); PhysicalDeviceSelector& set_required_features(VkPhysicalDeviceFeatures const& features);
#if defined(VKB_VK_API_VERSION_1_2) #if defined(VKB_VK_API_VERSION_1_2)
@ -659,9 +655,8 @@ class PhysicalDeviceSelector {
uint32_t desired_version = VKB_VK_API_VERSION_1_0; uint32_t desired_version = VKB_VK_API_VERSION_1_0;
VkPhysicalDeviceFeatures required_features{}; VkPhysicalDeviceFeatures required_features{};
#if defined(VK_KHR_get_physical_device_properties2) VkPhysicalDeviceFeatures2 required_features2{};
VkPhysicalDeviceFeatures2KHR required_features2{};
#endif
std::vector<detail::GenericFeaturesPNextNode> extended_features_chain; std::vector<detail::GenericFeaturesPNextNode> extended_features_chain;
bool defer_surface_initialization = false; bool defer_surface_initialization = false;
bool use_first_gpu_unconditionally = false; bool use_first_gpu_unconditionally = false;