Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate InstanceBuilder::set_minimum_instance_version, add InstanceBuilder::force_api_version, add SystemInfo::iis_instance_version_available #351

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@

`vk-bootstrap` reduces the complexity of dealing with `VkInstance`, `VkPhysicalDevice`, and `VkDevice`, the three things every Vulkan app needs to start.

- [Getting Started](#getting-started)
- [Build Pattern](#build-pattern)
- [Instance Creation](#instance-creation)
* [Versions](#versions)
* [Enabling Instance Level Extensions and Layers](#enabling-instance-level-extensions-and-layers)
- [Versions](#versions)
- [Enabling Instance Level Extensions and Layers](#enabling-instance-level-extensions-and-layers)
- [Physical Device Selection](#physical-device-selection)
- [Physical Device Object](#physical-device-object)
- [Device Creation](#device-creation)
* [Queues](#queues)
+ [Custom queue setup](#custom-queue-setup)
- [Queues](#queues)
- [Custom queue setup](#custom-queue-setup)
- [Dispatch Table](#dispatch-table)
- [WSI](#wsi)
* [For those who don't want a surface](#for-those-who-dont-want-a-surface)
* [Surface Creation](#surface-creation)
* [Swapchain](#swapchain)
- [For those who don't want a surface](#for-those-who-dont-want-a-surface)
- [Surface Creation](#surface-creation)
- [Swapchain](#swapchain)
- [Cleanup](#cleanup)
- [Creating your own debug callback](#creating-your-own-debug-callback)

Expand Down Expand Up @@ -74,10 +75,8 @@ instance_builder.set_app_version(3, 0, 0);
instance_builder.set_engine_version(5, 0, 2);

// The Instance Version (aka the version of your loader)
// TODO - which?
// This will make sure you require a 1.3 Vulkan Loader
instance_builder.require_api_version(1, 3, 0);
instance_builder.set_minimum_instance_version(1, 3, 0);
```

## Enabling Instance Level Extensions and Layers
Expand Down
4 changes: 2 additions & 2 deletions example/basic_usage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ bool init_vulkan() {
GLFWwindow* window = glfwCreateWindow(1024, 1024, "Vulkan Triangle", NULL, NULL);

VkSurfaceKHR surface = VK_NULL_HANDLE;
if (VkResult err = glfwCreateWindowSurface(vkb_inst, window, nullptr, &surface)) {
if (VK_SUCCESS != glfwCreateWindowSurface(vkb_inst, window, nullptr, &surface)) {
std::cerr << "Failed to select create windows surface\n";
return false;
}
Expand Down Expand Up @@ -79,4 +79,4 @@ int main() {
if (init_vulkan()) {
std::cout << "Boilerplate done, time to write you application!\n";
}
}
}
26 changes: 25 additions & 1 deletion src/VkBootstrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,15 @@ SystemInfo::SystemInfo() {
}
}
}

PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion = detail::vulkan_functions().fp_vkEnumerateInstanceVersion;

if (pfn_vkEnumerateInstanceVersion != nullptr) {
VkResult res = pfn_vkEnumerateInstanceVersion(&instance_api_version);
if (res != VK_SUCCESS) {
instance_api_version = VKB_VK_API_VERSION_1_0;
}
}
}
bool SystemInfo::is_extension_available(const char* extension_name) const {
if (!extension_name) return false;
Expand All @@ -560,6 +569,11 @@ bool SystemInfo::is_layer_available(const char* layer_name) const {
if (!layer_name) return false;
return detail::check_layer_supported(available_layers, layer_name);
}
bool SystemInfo::is_instance_version_available(uint32_t major_api_version, uint32_t minor_api_version) {
return instance_api_version >= VKB_MAKE_VK_VERSION(0, major_api_version, minor_api_version, 0);
}
bool SystemInfo::is_instance_version_available(uint32_t api_version) { return instance_api_version >= api_version; }

void destroy_surface(Instance const& instance, VkSurfaceKHR surface) {
if (instance.instance != VK_NULL_HANDLE && surface != VK_NULL_HANDLE) {
detail::vulkan_functions().fp_vkDestroySurfaceKHR(instance.instance, surface, instance.allocation_callbacks);
Expand Down Expand Up @@ -620,7 +634,9 @@ Result<Instance> InstanceBuilder::build() const {
}

uint32_t api_version = instance_version < VKB_VK_API_VERSION_1_1 ? instance_version : info.required_api_version;

if (info.forced_api_version > VKB_VK_API_VERSION_1_0) {
api_version = info.forced_api_version;
}
VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pNext = nullptr;
Expand Down Expand Up @@ -819,6 +835,14 @@ InstanceBuilder& InstanceBuilder::set_minimum_instance_version(uint32_t major, u
info.minimum_instance_version = VKB_MAKE_VK_VERSION(0, major, minor, patch);
return *this;
}
InstanceBuilder& InstanceBuilder::force_api_version(uint32_t major, uint32_t minor) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any meaningful suggestions so I'll bikeshed the name

What about set_api_version? force_api_version makes so... forceful

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This use case is kinda "advanced" API usage, so a scary name helps ward away unsuspecting users.

info.forced_api_version = VKB_MAKE_VK_VERSION(0, major, minor, 0);
return *this;
}
InstanceBuilder& InstanceBuilder::force_api_version(uint32_t forced_version) {
info.forced_api_version = forced_version;
return *this;
}
InstanceBuilder& InstanceBuilder::enable_layer(const char* layer_name) {
if (!layer_name) return *this;
info.layers.push_back(layer_name);
Expand Down
19 changes: 19 additions & 0 deletions src/VkBootstrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,18 @@ struct SystemInfo {
bool is_layer_available(const char* layer_name) const;
// Returns true if an extension is available
bool is_extension_available(const char* extension_name) const;
// Returns true if the Instance API Version is greater than or equal to the specified version
bool is_instance_version_available(uint32_t major_api_version, uint32_t minor_api_version);
// Returns true if the Instance API Version is greater than or equal to the specified version
// Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
bool is_instance_version_available(uint32_t api_version);

std::vector<VkLayerProperties> available_layers;
std::vector<VkExtensionProperties> available_extensions;
bool validation_layers_available = false;
bool debug_utils_available = false;

uint32_t instance_api_version = VKB_VK_API_VERSION_1_0;
};

// Forward declared - check VkBoostrap.cpp for implementations
Expand Down Expand Up @@ -388,10 +395,21 @@ class InstanceBuilder {

// Overrides required API version for instance creation. Will fail to create if this version isn't available.
// Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
[[deprecated("Use force_api_version")]]
InstanceBuilder& set_minimum_instance_version(uint32_t minimum_instance_version);
// Overrides required API version for instance creation. Will fail to create if this version isn't available.
[[deprecated("Use force_api_version")]]
InstanceBuilder& set_minimum_instance_version(uint32_t major, uint32_t minor, uint32_t patch = 0);

// Bypass normal instance version checking, allowing applications to specify an apiVersion higher than that of the
// instance. This version is passed onto PhysicalDevice selection as the minimum version.
InstanceBuilder& force_api_version(uint32_t major, uint32_t minor);
// Bypass normal instance version checking, allowing applications to specify an apiVersion higher than that of the instance.
// This version is passed onto PhysicalDevice selection as the minimum version.
// Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
InstanceBuilder& force_api_version(uint32_t forced_version);


// Adds a layer to be enabled. Will fail to create an instance if the layer isn't available.
InstanceBuilder& enable_layer(const char* layer_name);
// Adds an extension to be enabled. Will fail to create an instance if the extension isn't available.
Expand Down Expand Up @@ -446,6 +464,7 @@ class InstanceBuilder {
uint32_t engine_version = 0;
uint32_t minimum_instance_version = 0;
uint32_t required_api_version = VKB_VK_API_VERSION_1_0;
uint32_t forced_api_version = VKB_VK_API_VERSION_1_0;

// VkInstanceCreateInfo
std::vector<const char*> layers;
Expand Down
62 changes: 58 additions & 4 deletions tests/bootstrap_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
REQUIRE(sys_info_ret);

vkb::InstanceBuilder instance_builder;
auto instance_ret = instance_builder.require_api_version(1, 1, 0)
.set_minimum_instance_version(1, 0, 0)
.use_default_debug_messenger()
.build();
auto instance_ret = instance_builder.require_api_version(1, 1, 0).use_default_debug_messenger().build();
REQUIRE(instance_ret);
vkb::Instance instance = instance_ret.value();

Expand Down Expand Up @@ -455,6 +452,25 @@ TEST_CASE("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") {
REQUIRE(ret);
}

TEST_CASE("SystemInfo Check Instance API Version", "[VkBootstrap.instance_api_version]") {
VulkanMock& mock = get_and_setup_default();
mock.api_version = VK_API_VERSION_1_2;
auto info_ret = vkb::SystemInfo::get_system_info();
REQUIRE(info_ret);
auto system_info = info_ret.value();
REQUIRE(system_info.is_instance_version_available(VK_MAKE_API_VERSION(0, 1, 0, 0)));
REQUIRE(system_info.is_instance_version_available(VK_MAKE_API_VERSION(0, 1, 1, 0)));
REQUIRE(system_info.is_instance_version_available(VK_MAKE_API_VERSION(0, 1, 2, 0)));
REQUIRE(!system_info.is_instance_version_available(VK_MAKE_API_VERSION(0, 1, 3, 0)));
REQUIRE(!system_info.is_instance_version_available(VK_MAKE_API_VERSION(0, 1, 4, 0)));

REQUIRE(system_info.is_instance_version_available(1, 0));
REQUIRE(system_info.is_instance_version_available(1, 1));
REQUIRE(system_info.is_instance_version_available(1, 2));
REQUIRE(!system_info.is_instance_version_available(1, 3));
REQUIRE(!system_info.is_instance_version_available(1, 4));
}

TEST_CASE("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") {
[[maybe_unused]] VulkanMock& mock = get_and_setup_default();
VulkanLibrary vk_lib;
Expand Down Expand Up @@ -516,6 +532,44 @@ TEST_CASE("ReLoading Vulkan Manually", "[VkBootstrap.loading]") {
}
}

TEST_CASE("Force new API version than instance", "[VkBootstrap.api_version]") {
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_3;
mock.physical_devices_details[0].properties.deviceID = 1;
add_basic_physical_device(mock).properties.apiVersion = VK_API_VERSION_1_4;
mock.physical_devices_details[1].properties.deviceID = 2;
{
auto ret = vkb::InstanceBuilder{}.set_headless().require_api_version(1, 2).force_api_version(1, 4).build();
REQUIRE(ret);
auto pd_ret = vkb::PhysicalDeviceSelector{ ret.value() }.select();
REQUIRE(pd_ret);
REQUIRE(pd_ret.value().properties.deviceID == 2);
}
{
auto ret = vkb::InstanceBuilder{}
.set_headless()
.require_api_version(VK_MAKE_API_VERSION(0, 1, 2, 0))
.force_api_version(VK_MAKE_API_VERSION(0, 1, 4, 0))
.build();
REQUIRE(ret);
auto pd_ret = vkb::PhysicalDeviceSelector{ ret.value() }.select();
REQUIRE(pd_ret);
REQUIRE(pd_ret.value().properties.deviceID == 2);
}
}
TEST_CASE("Force new API version without supporting VkPhysicalDevice", "[VkBootstrap.api_version]") {
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_3;
mock.physical_devices_details[0].properties.deviceID = 1;
{
auto ret = vkb::InstanceBuilder{}.set_headless().require_api_version(1, 2).force_api_version(1, 4).build();
REQUIRE(ret);
auto pd_ret = vkb::PhysicalDeviceSelector{ ret.value() }.select();
REQUIRE(pd_ret.error() == vkb::PhysicalDeviceError::no_suitable_device);
}
}
TEST_CASE("Querying Required Extension Features but with 1.0", "[VkBootstrap.select_features]") {
VulkanMock& mock = get_and_setup_default();
mock.instance_extensions.push_back(get_extension_properties("VK_KHR_get_physical_device_properties2"));
Expand Down
5 changes: 1 addition & 4 deletions tests/vulkan_hpp_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ TEST_CASE("VulkanHpp Instance with surface", "[VkBootstrap.vulkan_hpp]") {
REQUIRE(sys_info_ret);

vkb::InstanceBuilder instance_builder;
auto instance_ret = instance_builder.require_api_version(1, 1, 0)
.set_minimum_instance_version(1, 0, 0)
.use_default_debug_messenger()
.build();
auto instance_ret = instance_builder.require_api_version(1, 1, 0).use_default_debug_messenger().build();
REQUIRE(instance_ret);
vkb::Instance instance = instance_ret.value();
vk::Instance hpp_instance{ instance };
Expand Down
7 changes: 6 additions & 1 deletion tests/vulkan_mock_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ VulkanMock& get_and_setup_default() {
mock.instance_extensions.push_back(get_extension_properties("VK_EXT_metal_surface"));
#endif
mock.instance_extensions.push_back(get_extension_properties(VK_EXT_DEBUG_UTILS_EXTENSION_NAME));
add_basic_physical_device(mock);
return mock;
}

VulkanMock::PhysicalDeviceDetails& add_basic_physical_device(VulkanMock& mock) {
VulkanMock::PhysicalDeviceDetails physical_device_details{};
physical_device_details.extensions.push_back(get_extension_properties(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
physical_device_details.properties.apiVersion = VK_API_VERSION_1_0;
Expand All @@ -45,7 +50,7 @@ VulkanMock& get_and_setup_default() {
queue_family_properties.minImageTransferGranularity = { 1, 1, 1 };
physical_device_details.queue_family_properties.push_back(queue_family_properties);
mock.add_physical_device(std::move(physical_device_details));
return mock;
return mock.physical_devices_details.back();
}

VulkanMock::SurfaceDetails get_basic_surface_details() {
Expand Down
2 changes: 2 additions & 0 deletions tests/vulkan_mock_setup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ VkExtensionProperties get_extension_properties(const char* extName);

VulkanMock& get_and_setup_default();

VulkanMock::PhysicalDeviceDetails& add_basic_physical_device(VulkanMock& mock);

VulkanMock::SurfaceDetails get_basic_surface_details();