Error handling with std::error_code

This commit is contained in:
Lesley Lai 2020-05-17 07:31:02 -06:00
parent 120a162264
commit df53490ede
7 changed files with 367 additions and 169 deletions

View File

@ -11,7 +11,7 @@ Simply create a builder variable and call the `build()` member function.
vkb::InstanceBuilder instance_builder; vkb::InstanceBuilder instance_builder;
auto instance_builder_return = instance_builder.build(); auto instance_builder_return = instance_builder.build();
``` ```
Because creating an instance may fail, the builder returns an 'Expected' type. This contains either a valid `vkb::Instance` struct, which includes a `VkInstance` handle, or contains an `vkb::InstanceError`. Because creating an instance may fail, the builder returns an 'Result' type. This contains either a valid `vkb::Instance` struct, which includes a `VkInstance` handle, or contains an `vkb::InstanceError`.
```cpp ```cpp
if (!instance_builder_return) { if (!instance_builder_return) {
printf("Failed to create Vulkan instance. Cause %s\n", printf("Failed to create Vulkan instance. Cause %s\n",
@ -19,7 +19,7 @@ if (!instance_builder_return) {
return -1; return -1;
} }
``` ```
Once any possible errors have been dealt with, we can pull the `vkb::Instance` struct out of the `Expected`. 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();
``` ```

View File

@ -44,7 +44,7 @@ int device_initialization (Init& init) {
vkb::InstanceBuilder instance_builder; vkb::InstanceBuilder instance_builder;
auto instance_ret = instance_builder.use_default_debug_messenger ().request_validation_layers ().build (); auto instance_ret = instance_builder.use_default_debug_messenger ().request_validation_layers ().build ();
if (!instance_ret) { if (!instance_ret) {
std::cout << vkb::to_string (instance_ret.error ().type) << "\n"; std::cout << instance_ret.error () << "\n";
return -1; return -1;
} }
init.instance = instance_ret.value (); init.instance = instance_ret.value ();
@ -54,7 +54,7 @@ int device_initialization (Init& init) {
vkb::PhysicalDeviceSelector phys_device_selector (init.instance); vkb::PhysicalDeviceSelector phys_device_selector (init.instance);
auto phys_device_ret = phys_device_selector.set_surface (init.surface).select (); auto phys_device_ret = phys_device_selector.set_surface (init.surface).select ();
if (!phys_device_ret) { if (!phys_device_ret) {
std::cout << vkb::to_string (phys_device_ret.error ().type) << "\n"; std::cout << phys_device_ret.error () << "\n";
return -1; return -1;
} }
vkb::PhysicalDevice physical_device = phys_device_ret.value (); vkb::PhysicalDevice physical_device = phys_device_ret.value ();
@ -62,7 +62,7 @@ int device_initialization (Init& init) {
vkb::DeviceBuilder device_builder{ physical_device }; vkb::DeviceBuilder device_builder{ physical_device };
auto device_ret = device_builder.build (); auto device_ret = device_builder.build ();
if (!device_ret) { if (!device_ret) {
std::cout << vkb::to_string (device_ret.error ().type) << "\n"; std::cout << device_ret.error () << "\n";
return -1; return -1;
} }
init.device = device_ret.value (); init.device = device_ret.value ();
@ -71,7 +71,7 @@ int device_initialization (Init& init) {
auto swap_ret = auto swap_ret =
swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build (); swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build ();
if (!swap_ret) { if (!swap_ret) {
std::cout << vkb::to_string (swap_ret.error ().type) << "\n"; std::cout << swap_ret.error () << "\n";
return -1; return -1;
} }
init.swapchain = swap_ret.value (); init.swapchain = swap_ret.value ();
@ -81,14 +81,14 @@ int device_initialization (Init& init) {
int get_queues (Init& init, RenderData& data) { int get_queues (Init& init, RenderData& data) {
auto gq = init.device.get_queue (vkb::QueueType::graphics); auto gq = init.device.get_queue (vkb::QueueType::graphics);
if (!gq.has_value ()) { if (!gq.has_value ()) {
std::cout << "failed to get graphics queue: " << vkb::to_string (gq.error ().type) << "\n"; std::cout << "failed to get graphics queue: " << gq.error () << "\n";
return -1; return -1;
} }
data.graphics_queue = gq.value (); data.graphics_queue = gq.value ();
auto pq = init.device.get_queue (vkb::QueueType::present); auto pq = init.device.get_queue (vkb::QueueType::present);
if (!pq.has_value ()) { if (!pq.has_value ()) {
std::cout << "failed to get present queue: " << vkb::to_string (gq.error ().type) << "\n"; std::cout << "failed to get present queue: " << pq.error () << "\n";
return -1; return -1;
} }
data.present_queue = pq.value (); data.present_queue = pq.value ();

View File

@ -15,22 +15,18 @@ void get_inst_proc_addr (
// Helper for robustly executing the two-call pattern // Helper for robustly executing the two-call pattern
template <typename T, typename F, typename... Ts> template <typename T, typename F, typename... Ts>
auto get_vector (F&& f, Ts&&... ts) -> Expected<std::vector<T>, VkResult> { auto get_vector (std::vector<T>& out, F&& f, Ts&&... ts) -> VkResult {
uint32_t count = 0; uint32_t count = 0;
std::vector<T> results;
VkResult err; VkResult err;
do { do {
err = f (ts..., &count, nullptr); err = f (ts..., &count, nullptr);
if (err) { if (err) {
return err; return err;
}; };
results.resize (count); out.resize (count);
err = f (ts..., &count, results.data ()); err = f (ts..., &count, out.data ());
} while (err == VK_INCOMPLETE); } while (err == VK_INCOMPLETE);
if (err != VK_SUCCESS) { return err;
return err;
};
return results;
} }
template <typename T, typename F, typename... Ts> template <typename T, typename F, typename... Ts>
@ -167,8 +163,64 @@ void setup_pNext_chain (T& structure, std::vector<VkBaseOutStructure*> const& st
} }
const char* validation_layer_name = "VK_LAYER_KHRONOS_validation"; const char* validation_layer_name = "VK_LAYER_KHRONOS_validation";
struct InstanceErrorCategory : std::error_category {
const char* name () const noexcept override { return "vkb_instance"; }
std::string message (int err) const override {
return to_string (static_cast<InstanceError> (err));
}
};
const InstanceErrorCategory instance_error_category;
struct PhysicalDeviceErrorCategory : std::error_category {
const char* name () const noexcept override { return "vkb_physical_device"; }
std::string message (int err) const override {
return to_string (static_cast<PhysicalDeviceError> (err));
}
};
const PhysicalDeviceErrorCategory physical_device_error_category;
struct QueueErrorCategory : std::error_category {
const char* name () const noexcept override { return "vkb_queue"; }
std::string message (int err) const override {
return to_string (static_cast<QueueError> (err));
}
};
const QueueErrorCategory queue_error_category;
struct DeviceErrorCategory : std::error_category {
const char* name () const noexcept override { return "vkb_device"; }
std::string message (int err) const override {
return to_string (static_cast<DeviceError> (err));
}
};
const DeviceErrorCategory device_error_category;
struct SwapchainErrorCategory : std::error_category {
const char* name () const noexcept override { return "vbk_swapchain"; }
std::string message (int err) const override {
return to_string (static_cast<SwapchainError> (err));
}
};
const SwapchainErrorCategory swapchain_error_category;
} // namespace detail } // namespace detail
std::error_code make_error_code (InstanceError instance_error) {
return { static_cast<int> (instance_error), detail::instance_error_category };
}
std::error_code make_error_code (PhysicalDeviceError physical_device_error) {
return { static_cast<int> (physical_device_error), detail::physical_device_error_category };
}
std::error_code make_error_code (QueueError queue_error) {
return { static_cast<int> (queue_error), detail::queue_error_category };
}
std::error_code make_error_code (DeviceError device_error) {
return { static_cast<int> (device_error), detail::device_error_category };
}
std::error_code make_error_code (SwapchainError swapchain_error) {
return { static_cast<int> (swapchain_error), detail::swapchain_error_category };
}
const char* to_string (InstanceError err) { const char* to_string (InstanceError err) {
switch (err) { switch (err) {
case InstanceError::vulkan_unavailable: case InstanceError::vulkan_unavailable:
@ -249,19 +301,22 @@ const char* to_string (SwapchainError err) {
} }
SystemInfo::SystemInfo () { SystemInfo::SystemInfo () {
auto available_extensions_ret = auto available_extensions_ret = detail::get_vector<VkExtensionProperties> (
detail::get_vector<VkExtensionProperties> (vkEnumerateInstanceExtensionProperties, nullptr); this->available_extensions, vkEnumerateInstanceExtensionProperties, nullptr);
if (available_extensions_ret.has_value ()) { if (available_extensions_ret != VK_SUCCESS) {
this->available_extensions = available_extensions_ret.value (); this->available_extensions.clear ();
} }
for (auto& ext : this->available_extensions) for (auto& ext : this->available_extensions)
if (strcmp (ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) if (strcmp (ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
debug_messenger_available = true; debug_messenger_available = true;
auto available_layers_ret = detail::get_vector<VkLayerProperties> (vkEnumerateInstanceLayerProperties); auto available_layers_ret =
if (available_layers_ret.has_value ()) { detail::get_vector<VkLayerProperties> (this->available_layers, vkEnumerateInstanceLayerProperties);
this->available_layers = available_layers_ret.value (); if (available_layers_ret != VK_SUCCESS) {
this->available_layers.clear ();
} }
for (auto& layer : this->available_layers) for (auto& layer : this->available_layers)
if (strcmp (layer.layerName, detail::validation_layer_name) == 0) if (strcmp (layer.layerName, detail::validation_layer_name) == 0)
validation_layers_available = true; validation_layers_available = true;
@ -285,7 +340,7 @@ void destroy_instance (Instance instance) {
SystemInfo InstanceBuilder::get_system_info () const { return system; } SystemInfo InstanceBuilder::get_system_info () const { return system; }
detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build () const { detail::Result<Instance> InstanceBuilder::build () const {
uint32_t api_version = VK_MAKE_VERSION (1, 0, 0); uint32_t api_version = VK_MAKE_VERSION (1, 0, 0);
@ -300,15 +355,15 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
VkResult res = pfn_vkEnumerateInstanceVersion (&queried_api_version); VkResult res = pfn_vkEnumerateInstanceVersion (&queried_api_version);
// Should always return VK_SUCCESS // Should always return VK_SUCCESS
if (res != VK_SUCCESS && info.required_api_version > 0) if (res != VK_SUCCESS && info.required_api_version > 0)
return detail::Error<InstanceError>{ InstanceError::vulkan_version_unavailable }; return make_error_code (InstanceError::vulkan_version_unavailable);
} }
if (pfn_vkEnumerateInstanceVersion == nullptr || queried_api_version < info.required_api_version) { if (pfn_vkEnumerateInstanceVersion == nullptr || queried_api_version < info.required_api_version) {
if (VK_VERSION_MINOR (info.required_api_version) == 2) if (VK_VERSION_MINOR (info.required_api_version) == 2)
return detail::Error<InstanceError>{ InstanceError::vulkan_version_1_2_unavailable }; return make_error_code (InstanceError::vulkan_version_1_2_unavailable);
else if (VK_VERSION_MINOR (info.required_api_version)) else if (VK_VERSION_MINOR (info.required_api_version))
return detail::Error<InstanceError>{ InstanceError::vulkan_version_1_1_unavailable }; return make_error_code (InstanceError::vulkan_version_1_1_unavailable);
else else
return detail::Error<InstanceError>{ InstanceError::vulkan_version_unavailable }; return make_error_code (InstanceError::vulkan_version_unavailable);
} }
if (info.required_api_version > VK_MAKE_VERSION (1, 0, 0)) { if (info.required_api_version > VK_MAKE_VERSION (1, 0, 0)) {
api_version = info.required_api_version; api_version = info.required_api_version;
@ -354,7 +409,7 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
} }
bool all_extensions_supported = detail::check_extensions_supported (system.available_extensions, extensions); bool all_extensions_supported = detail::check_extensions_supported (system.available_extensions, extensions);
if (!all_extensions_supported) { if (!all_extensions_supported) {
return detail::Error<InstanceError>{ InstanceError::requested_extensions_not_present }; return make_error_code (InstanceError::requested_extensions_not_present);
} }
std::vector<const char*> layers; std::vector<const char*> layers;
@ -366,7 +421,7 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
} }
bool all_layers_supported = detail::check_layers_supported (system.available_layers, layers); bool all_layers_supported = detail::check_layers_supported (system.available_layers, layers);
if (!all_layers_supported) { if (!all_layers_supported) {
return detail::Error<InstanceError>{ InstanceError::requested_layers_not_present }; return make_error_code (InstanceError::requested_layers_not_present);
} }
std::vector<VkBaseOutStructure*> pNext_chain; std::vector<VkBaseOutStructure*> pNext_chain;
@ -417,7 +472,7 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
Instance instance; Instance instance;
VkResult res = vkCreateInstance (&instance_create_info, info.allocation_callbacks, &instance.instance); VkResult res = vkCreateInstance (&instance_create_info, info.allocation_callbacks, &instance.instance);
if (res != VK_SUCCESS) if (res != VK_SUCCESS)
return detail::Error<InstanceError>{ InstanceError::failed_create_instance, res }; return detail::Result<Instance> (InstanceError::failed_create_instance, res);
if (info.use_debug_messenger) { if (info.use_debug_messenger) {
res = create_debug_utils_messenger (instance.instance, res = create_debug_utils_messenger (instance.instance,
@ -427,7 +482,7 @@ detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build
&instance.debug_messenger, &instance.debug_messenger,
info.allocation_callbacks); info.allocation_callbacks);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return detail::Error<InstanceError>{ InstanceError::failed_create_debug_messenger, res }; return detail::Result<Instance> (InstanceError::failed_create_debug_messenger, res);
} }
} }
@ -538,12 +593,13 @@ namespace detail {
std::vector<const char*> check_device_extension_support ( std::vector<const char*> check_device_extension_support (
VkPhysicalDevice device, std::vector<const char*> desired_extensions) { VkPhysicalDevice device, std::vector<const char*> desired_extensions) {
auto available_extensions = std::vector<VkExtensionProperties> available_extensions;
detail::get_vector<VkExtensionProperties> (vkEnumerateDeviceExtensionProperties, device, nullptr); auto available_extensions_ret = detail::get_vector<VkExtensionProperties> (
if (!available_extensions.has_value ()) return {}; available_extensions, vkEnumerateDeviceExtensionProperties, device, nullptr);
if (available_extensions_ret != VK_SUCCESS) return {};
std::vector<const char*> extensions_to_enable; std::vector<const char*> extensions_to_enable;
for (const auto& extension : available_extensions.value ()) { for (const auto& extension : available_extensions) {
for (auto& req_ext : desired_extensions) { for (auto& req_ext : desired_extensions) {
if (strcmp (req_ext, extension.extensionName) == 0) { if (strcmp (req_ext, extension.extensionName) == 0) {
extensions_to_enable.push_back (req_ext); extensions_to_enable.push_back (req_ext);
@ -742,14 +798,16 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable (Phy
if (criteria.defer_surface_initialization) { if (criteria.defer_surface_initialization) {
swapChainAdequate = true; swapChainAdequate = true;
} else if (!system_info.headless) { } else if (!system_info.headless) {
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> present_modes;
auto formats = detail::get_vector<VkSurfaceFormatKHR> ( auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (
vkGetPhysicalDeviceSurfaceFormatsKHR, pd.phys_device, system_info.surface); formats, vkGetPhysicalDeviceSurfaceFormatsKHR, pd.phys_device, system_info.surface);
auto present_modes = detail::get_vector<VkPresentModeKHR> ( auto present_modes_ret = detail::get_vector<VkPresentModeKHR> (
vkGetPhysicalDeviceSurfacePresentModesKHR, pd.phys_device, system_info.surface); present_modes, vkGetPhysicalDeviceSurfacePresentModesKHR, pd.phys_device, system_info.surface);
if (formats.has_value () && present_modes.has_value ()) { if (formats_ret == VK_SUCCESS && present_modes_ret == VK_SUCCESS) {
swapChainAdequate = !formats.value ().empty () && !present_modes.value ().empty (); swapChainAdequate = !formats.empty () && !present_modes.empty ();
} }
} }
if (criteria.require_present && !swapChainAdequate) return Suitable::no; if (criteria.require_present && !swapChainAdequate) return Suitable::no;
@ -791,24 +849,27 @@ PhysicalDeviceSelector::PhysicalDeviceSelector (Instance const& instance) {
criteria.desired_version = instance.instance_version; criteria.desired_version = instance.instance_version;
} }
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> PhysicalDeviceSelector::select () const { detail::Result<PhysicalDevice> PhysicalDeviceSelector::select () const {
if (!system_info.headless && !criteria.defer_surface_initialization) { if (!system_info.headless && !criteria.defer_surface_initialization) {
if (system_info.surface == nullptr) if (system_info.surface == nullptr)
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::no_surface_provided }; return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_surface_provided };
} }
auto physical_devices =
detail::get_vector<VkPhysicalDevice> (vkEnumeratePhysicalDevices, system_info.instance); std::vector<VkPhysicalDevice> physical_devices;
if (!physical_devices.has_value ()) {
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::failed_enumerate_physical_devices, auto physical_devices_ret = detail::get_vector<VkPhysicalDevice> (
physical_devices.error () }; physical_devices, vkEnumeratePhysicalDevices, system_info.instance);
if (physical_devices_ret != VK_SUCCESS) {
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::failed_enumerate_physical_devices,
physical_devices_ret };
} }
if (physical_devices.value ().size () == 0) { if (physical_devices.size () == 0) {
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::no_physical_devices_found }; return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_physical_devices_found };
} }
std::vector<PhysicalDeviceDesc> phys_device_descriptions; std::vector<PhysicalDeviceDesc> phys_device_descriptions;
for (auto& phys_device : physical_devices.value ()) { for (auto& phys_device : physical_devices) {
phys_device_descriptions.push_back (populate_device_details (phys_device)); phys_device_descriptions.push_back (populate_device_details (phys_device));
} }
@ -829,7 +890,7 @@ detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> PhysicalDev
} }
if (selected_device.phys_device == VK_NULL_HANDLE) { if (selected_device.phys_device == VK_NULL_HANDLE) {
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::no_suitable_device }; return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_suitable_device };
} }
PhysicalDevice out_device{}; PhysicalDevice out_device{};
out_device.physical_device = selected_device.phys_device; out_device.physical_device = selected_device.phys_device;
@ -949,43 +1010,43 @@ std::vector<VkQueueFamilyProperties> PhysicalDevice::get_queue_families () const
// ---- Queues ---- // // ---- Queues ---- //
detail::Expected<uint32_t, detail::Error<QueueError>> Device::get_queue_index (QueueType type) const { detail::Result<uint32_t> Device::get_queue_index (QueueType type) const {
int index = -1; int index = -1;
switch (type) { switch (type) {
case QueueType::present: case QueueType::present:
index = detail::get_present_queue_index (physical_device.physical_device, surface, queue_families); index = detail::get_present_queue_index (physical_device.physical_device, surface, queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::present_unavailable }; if (index < 0) return detail::Result<uint32_t>{ QueueError::present_unavailable };
break; break;
case QueueType::graphics: case QueueType::graphics:
index = detail::get_graphics_queue_index (queue_families); index = detail::get_graphics_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::graphics_unavailable }; if (index < 0) return detail::Result<uint32_t>{ QueueError::graphics_unavailable };
break; break;
case QueueType::compute: case QueueType::compute:
index = detail::get_separate_compute_queue_index (queue_families); index = detail::get_separate_compute_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable }; if (index < 0) return detail::Result<uint32_t>{ QueueError::compute_unavailable };
break; break;
case QueueType::transfer: case QueueType::transfer:
index = detail::get_separate_transfer_queue_index (queue_families); index = detail::get_separate_transfer_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable }; if (index < 0) return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
break; break;
default: default:
return detail::Error<QueueError>{ QueueError::invalid_queue_family_index }; return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index };
} }
return static_cast<uint32_t> (index); return static_cast<uint32_t> (index);
} }
detail::Expected<uint32_t, detail::Error<QueueError>> Device::get_dedicated_queue_index (QueueType type) const { detail::Result<uint32_t> Device::get_dedicated_queue_index (QueueType type) const {
int index = -1; int index = -1;
switch (type) { switch (type) {
case QueueType::compute: case QueueType::compute:
index = detail::get_dedicated_compute_queue_index (queue_families); index = detail::get_dedicated_compute_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable }; if (index < 0) return detail::Result<uint32_t>{ QueueError::compute_unavailable };
break; break;
case QueueType::transfer: case QueueType::transfer:
index = detail::get_dedicated_transfer_queue_index (queue_families); index = detail::get_dedicated_transfer_queue_index (queue_families);
if (index < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable }; if (index < 0) return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
break; break;
default: default:
return detail::Error<QueueError>{ QueueError::invalid_queue_family_index }; return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index };
} }
return static_cast<uint32_t> (index); return static_cast<uint32_t> (index);
} }
@ -996,14 +1057,14 @@ VkQueue get_queue (VkDevice device, uint32_t family) {
return out_queue; return out_queue;
} }
} // namespace detail } // namespace detail
detail::Expected<VkQueue, detail::Error<QueueError>> Device::get_queue (QueueType type) const { detail::Result<VkQueue> Device::get_queue (QueueType type) const {
auto index = get_queue_index (type); auto index = get_queue_index (type);
if (!index.has_value ()) return index.error (); if (!index.has_value ()) return { index.error () };
return detail::get_queue (device, index.value ()); return detail::get_queue (device, index.value ());
} }
detail::Expected<VkQueue, detail::Error<QueueError>> Device::get_dedicated_queue (QueueType type) const { detail::Result<VkQueue> Device::get_dedicated_queue (QueueType type) const {
auto index = get_dedicated_queue_index (type); auto index = get_dedicated_queue_index (type);
if (!index.has_value ()) return index.error (); if (!index.has_value ()) return { index.error () };
return detail::get_queue (device, index.value ()); return detail::get_queue (device, index.value ());
} }
@ -1027,7 +1088,7 @@ DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device) {
info.defer_surface_initialization = phys_device.defer_surface_initialization; info.defer_surface_initialization = phys_device.defer_surface_initialization;
} }
detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () const { detail::Result<Device> DeviceBuilder::build () const {
std::vector<CustomQueueDescription> queue_descriptions; std::vector<CustomQueueDescription> queue_descriptions;
queue_descriptions.insert ( queue_descriptions.insert (
@ -1079,7 +1140,7 @@ detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () con
info.allocation_callbacks, info.allocation_callbacks,
&device.device); &device.device);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return detail::Error<DeviceError>{ DeviceError::failed_create_device, res }; return { DeviceError::failed_create_device, res };
} }
device.physical_device = info.physical_device; device.physical_device = info.physical_device;
device.surface = info.surface; device.surface = info.surface;
@ -1112,27 +1173,51 @@ enum class SurfaceSupportError {
failed_enumerate_present_modes failed_enumerate_present_modes
}; };
Expected<SurfaceSupportDetails, detail::Error<SurfaceSupportError>> query_surface_support_details ( struct SurfaceSupportErrorCategory : std::error_category {
VkPhysicalDevice phys_device, VkSurfaceKHR surface) { const char* name () const noexcept override { return "vbk_surface_support"; }
std::string message (int err) const override {
switch (static_cast<SurfaceSupportError> (err)) {
case SurfaceSupportError::surface_handle_null:
return "surface_handle_null";
case SurfaceSupportError::failed_get_surface_capabilities:
return "failed_get_surface_capabilities";
case SurfaceSupportError::failed_enumerate_surface_formats:
return "failed_enumerate_surface_formats";
case SurfaceSupportError::failed_enumerate_present_modes:
return "failed_enumerate_present_modes";
default:
return "";
}
}
};
const SurfaceSupportErrorCategory surface_support_error_category;
std::error_code make_error_code (SurfaceSupportError surface_support_error) {
return { static_cast<int> (surface_support_error), detail::surface_support_error_category };
}
Result<SurfaceSupportDetails> query_surface_support_details (VkPhysicalDevice phys_device, VkSurfaceKHR surface) {
if (surface == VK_NULL_HANDLE) if (surface == VK_NULL_HANDLE)
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::surface_handle_null }; return make_error_code (SurfaceSupportError::surface_handle_null);
VkSurfaceCapabilitiesKHR capabilities; VkSurfaceCapabilitiesKHR capabilities;
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities); VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_get_surface_capabilities, res }; return { make_error_code (SurfaceSupportError::failed_get_surface_capabilities), res };
} }
auto formats = detail::get_vector<VkSurfaceFormatKHR> (
vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface); std::vector<VkSurfaceFormatKHR> formats;
if (!formats.has_value ()) std::vector<VkPresentModeKHR> present_modes;
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_enumerate_surface_formats,
formats.error () }; auto formats_ret = detail::get_vector<VkSurfaceFormatKHR> (
auto present_modes = detail::get_vector<VkPresentModeKHR> ( formats, vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface); if (formats_ret != VK_SUCCESS)
if (!present_modes.has_value ()) return { make_error_code (SurfaceSupportError::failed_enumerate_surface_formats), formats_ret };
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_enumerate_present_modes, auto present_modes_ret = detail::get_vector<VkPresentModeKHR> (
formats.error () }; present_modes, vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () }; if (present_modes_ret != VK_SUCCESS)
return { make_error_code (SurfaceSupportError::failed_enumerate_present_modes), present_modes_ret };
return SurfaceSupportDetails{ capabilities, formats, present_modes };
} }
VkSurfaceFormatKHR find_surface_format (std::vector<VkSurfaceFormatKHR> const& available_formats, VkSurfaceFormatKHR find_surface_format (std::vector<VkSurfaceFormatKHR> const& available_formats,
@ -1220,13 +1305,10 @@ SwapchainBuilder::SwapchainBuilder (
info.graphics_queue_index = static_cast<uint32_t> (graphics_queue_index); info.graphics_queue_index = static_cast<uint32_t> (graphics_queue_index);
info.present_queue_index = static_cast<uint32_t> (present_queue_index); info.present_queue_index = static_cast<uint32_t> (present_queue_index);
} }
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::build () const { detail::Result<Swapchain> SwapchainBuilder::build () const { return build (VK_NULL_HANDLE); }
return build (VK_NULL_HANDLE); detail::Result<Swapchain> SwapchainBuilder::build (VkSwapchainKHR old_swapchain) const {
}
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::build (
VkSwapchainKHR old_swapchain) const {
if (info.surface == VK_NULL_HANDLE) { if (info.surface == VK_NULL_HANDLE) {
return detail::Error<SwapchainError>{ SwapchainError::surface_handle_not_provided }; return detail::Error{ SwapchainError::surface_handle_not_provided };
} }
auto desired_formats = info.desired_formats; auto desired_formats = info.desired_formats;
@ -1236,8 +1318,8 @@ detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::bui
auto surface_support = detail::query_surface_support_details (info.physical_device, info.surface); auto surface_support = detail::query_surface_support_details (info.physical_device, info.surface);
if (!surface_support.has_value ()) if (!surface_support.has_value ())
return detail::Error<SwapchainError>{ SwapchainError::failed_query_surface_support_details, return detail::Error{ SwapchainError::failed_query_surface_support_details,
surface_support.error ().vk_result }; surface_support.vk_result () };
VkSurfaceFormatKHR surface_format = VkSurfaceFormatKHR surface_format =
detail::find_surface_format (surface_support.value ().formats, desired_formats); detail::find_surface_format (surface_support.value ().formats, desired_formats);
VkPresentModeKHR present_mode = VkPresentModeKHR present_mode =
@ -1281,32 +1363,33 @@ detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::bui
VkResult res = vkCreateSwapchainKHR ( VkResult res = vkCreateSwapchainKHR (
info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain); info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return detail::Error<SwapchainError>{ SwapchainError::failed_create_swapchain, res }; return detail::Error{ SwapchainError::failed_create_swapchain, res };
} }
swapchain.device = info.device; swapchain.device = info.device;
swapchain.image_format = surface_format.format; swapchain.image_format = surface_format.format;
swapchain.extent = extent; swapchain.extent = extent;
auto images = swapchain.get_images (); auto images = swapchain.get_images ();
if (!images) { if (!images) {
return detail::Error<SwapchainError>{ SwapchainError::failed_get_swapchain_images }; return detail::Error{ SwapchainError::failed_get_swapchain_images };
} }
swapchain.image_count = static_cast<uint32_t> (images.value ().size ()); swapchain.image_count = static_cast<uint32_t> (images.value ().size ());
swapchain.allocation_callbacks = info.allocation_callbacks; swapchain.allocation_callbacks = info.allocation_callbacks;
return swapchain; return swapchain;
} }
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::recreate ( detail::Result<Swapchain> SwapchainBuilder::recreate (Swapchain const& swapchain) const {
Swapchain const& swapchain) const {
return build (swapchain.swapchain); return build (swapchain.swapchain);
} }
detail::Expected<std::vector<VkImage>, detail::Error<SwapchainError>> Swapchain::get_images () { detail::Result<std::vector<VkImage>> Swapchain::get_images () {
auto swapchain_images = detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, device, swapchain); std::vector<VkImage> swapchain_images;
if (!swapchain_images) {
return detail::Error<SwapchainError>{ SwapchainError::failed_get_swapchain_images, auto swapchain_images_ret =
swapchain_images.error () }; detail::get_vector<VkImage> (swapchain_images, vkGetSwapchainImagesKHR, device, swapchain);
if (swapchain_images_ret != VK_SUCCESS) {
return detail::Error{ SwapchainError::failed_get_swapchain_images, swapchain_images_ret };
} }
return swapchain_images.value (); return swapchain_images;
} }
detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>> Swapchain::get_image_views () { detail::Result<std::vector<VkImageView>> Swapchain::get_image_views () {
auto swapchain_images_ret = get_images (); auto swapchain_images_ret = get_images ();
if (!swapchain_images_ret) return swapchain_images_ret.error (); if (!swapchain_images_ret) return swapchain_images_ret.error ();
@ -1332,7 +1415,7 @@ detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>> Swapch
VkResult res = vkCreateImageView (device, &createInfo, allocation_callbacks, &views[i]); VkResult res = vkCreateImageView (device, &createInfo, allocation_callbacks, &views[i]);
if (res != VK_SUCCESS) if (res != VK_SUCCESS)
return detail::Error<SwapchainError>{ SwapchainError::failed_create_swapchain_image_views, res }; return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res };
} }
return views; return views;
} }

View File

@ -3,93 +3,94 @@
#include <cassert> #include <cassert>
#include <vector> #include <vector>
#include <system_error>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
namespace vkb { namespace vkb {
namespace detail { namespace detail {
template <typename ErrorType> struct Error {
explicit Error (ErrorType type, VkResult result = VK_SUCCESS)
: type (type), vk_result (result) {}
ErrorType type; struct Error {
VkResult vk_result; // optional error value if a vulkan call failed std::error_code type;
VkResult vk_result = VK_SUCCESS; // optional error value if a vulkan call failed
}; };
template <typename E, typename U> class Expected { template <typename T> class Result {
public: public:
Expected (const E& expect) : m_expect{ expect }, m_init{ true } {} Result (const T& value) : m_value{ value }, m_init{ true } {}
Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {} Result (T&& value) : m_value{ std::move (value) }, m_init{ true } {}
Expected (const U& error) : m_error{ error }, m_init{ false } {}
Expected (U&& error) : m_error{ std::move (error) }, m_init{ false } {} Result (Error error) : m_error{ error }, m_init{ false } {}
~Expected () { destroy (); }
Expected (Expected const& expected) : m_init (expected.m_init) { Result (std::error_code error_code, VkResult result = VK_SUCCESS)
: m_error{ error_code, result }, m_init{ false } {}
~Result () { destroy (); }
Result (Result const& expected) : m_init (expected.m_init) {
if (m_init) if (m_init)
new (&m_expect) E{ expected.m_expect }; new (&m_value) T{ expected.m_value };
else else
new (&m_error) U{ expected.m_error }; m_error = expected.m_error;
} }
Expected (Expected&& expected) : m_init (expected.m_init) { Result (Result&& expected) : m_init (expected.m_init) {
if (m_init) if (m_init)
new (&m_expect) E{ std::move (expected.m_expect) }; new (&m_value) T{ std::move (expected.m_value) };
else else
new (&m_error) U{ std::move (expected.m_error) }; m_error = std::move (expected.m_error);
expected.destroy (); expected.destroy ();
} }
Expected& operator= (const E& expect) { Result& operator= (const T& expect) {
destroy (); destroy ();
m_init = true; m_init = true;
new (&m_expect) E{ expect }; new (&m_value) T{ expect };
return *this; return *this;
} }
Expected& operator= (E&& expect) { Result& operator= (T&& expect) {
destroy (); destroy ();
m_init = true; m_init = true;
new (&m_expect) E{ std::move (expect) }; new (&m_value) T{ std::move (expect) };
return *this; return *this;
} }
Expected& operator= (const U& error) { Result& operator= (const Error& error) {
destroy (); destroy ();
m_init = false; m_init = false;
new (&m_error) U{ error }; m_error = error;
return *this; return *this;
} }
Expected& operator= (U&& error) { Result& operator= (Error&& error) {
destroy (); destroy ();
m_init = false; m_init = false;
new (&m_error) U{ std::move (error) }; m_error = error;
return *this; return *this;
} }
// clang-format off // clang-format off
const E* operator-> () const { assert (m_init); return &m_expect; } const T* operator-> () const { assert (m_init); return &m_value; }
E* operator-> () { assert (m_init); return &m_expect; } T* operator-> () { assert (m_init); return &m_value; }
const E& operator* () const& { assert (m_init); return m_expect; } const T& operator* () const& { assert (m_init); return m_value; }
E& operator* () & { assert (m_init); return m_expect; } T& operator* () & { assert (m_init); return m_value; }
E&& operator* () && { assert (m_init); return std::move (m_expect); } T&& operator* () && { assert (m_init); return std::move (m_value); }
const E& value () const& { assert (m_init); return m_expect; } const T& value () const& { assert (m_init); return m_value; }
E& value () & { assert (m_init); return m_expect; } T& value () & { assert (m_init); return m_value; }
const E&& value () const&& { assert (m_init); return std::move (m_expect); } const T&& value () const&& { assert (m_init); return std::move (m_value); }
E&& value () && { assert (m_init); return std::move (m_expect); } T&& value () && { assert (m_init); return std::move (m_value); }
const U& error () const& { assert (!m_init); return m_error; }
U& error () & { assert (!m_init); return m_error; } std::error_code error() const { assert (!m_init); return m_error.type; }
const U&& error () const&& { assert (!m_init); return std::move (m_error); } VkResult vk_result() const { assert (!m_init); return m_error.vk_result; }
U&& error () && { assert (!m_init); return std::move (m_error); }
// clang-format on // clang-format on
bool has_value () const { return m_init; } bool has_value () const { return m_init; }
explicit operator bool () const { return m_init; } explicit operator bool () const { return m_init; }
private: private:
void destroy () { void destroy () {
if (m_init) if (m_init) m_value.~T ();
m_expect.~E ();
else
m_error.~U ();
} }
union { union {
E m_expect; T m_value;
U m_error; Error m_error;
}; };
bool m_init; bool m_init;
}; };
@ -131,6 +132,13 @@ enum class SwapchainError {
failed_get_swapchain_images, failed_get_swapchain_images,
failed_create_swapchain_image_views, failed_create_swapchain_image_views,
}; };
std::error_code make_error_code (InstanceError instance_error);
std::error_code make_error_code (PhysicalDeviceError physical_device_error);
std::error_code make_error_code (QueueError queue_error);
std::error_code make_error_code (DeviceError device_error);
std::error_code make_error_code (SwapchainError swapchain_error);
const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s); const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s);
const char* to_string_message_type (VkDebugUtilsMessageTypeFlagsEXT s); const char* to_string_message_type (VkDebugUtilsMessageTypeFlagsEXT s);
@ -178,7 +186,7 @@ class InstanceBuilder {
SystemInfo get_system_info () const; SystemInfo get_system_info () const;
// Create a VkInstance. Return an error if it failed. // Create a VkInstance. Return an error if it failed.
detail::Expected<Instance, detail::Error<InstanceError>> build () const; detail::Result<Instance> build () const;
// Sets the name of the application. Defaults to "" if none is provided. // Sets the name of the application. Defaults to "" if none is provided.
InstanceBuilder& set_app_name (const char* app_name); InstanceBuilder& set_app_name (const char* app_name);
@ -336,7 +344,7 @@ class PhysicalDeviceSelector {
// Requires a vkb::Instance to construct, needed to pass instance creation info. // Requires a vkb::Instance to construct, needed to pass instance creation info.
PhysicalDeviceSelector (Instance const& instance); PhysicalDeviceSelector (Instance const& instance);
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> select () const; detail::Result<PhysicalDevice> select () const;
// Set the surface in which the physical device should render to. // Set the surface in which the physical device should render to.
PhysicalDeviceSelector& set_surface (VkSurfaceKHR surface); PhysicalDeviceSelector& set_surface (VkSurfaceKHR surface);
@ -446,13 +454,13 @@ struct Device {
std::vector<VkQueueFamilyProperties> queue_families; std::vector<VkQueueFamilyProperties> queue_families;
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
detail::Expected<uint32_t, detail::Error<QueueError>> get_queue_index (QueueType type) const; detail::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 // Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue index
detail::Expected<uint32_t, detail::Error<QueueError>> get_dedicated_queue_index (QueueType type) const; detail::Result<uint32_t> get_dedicated_queue_index (QueueType type) const;
detail::Expected<VkQueue, detail::Error<QueueError>> get_queue (QueueType type) const; detail::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 // Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue
detail::Expected<VkQueue, detail::Error<QueueError>> get_dedicated_queue (QueueType type) const; detail::Result<VkQueue> get_dedicated_queue (QueueType type) const;
}; };
// For advanced device queue setup // For advanced device queue setup
@ -470,7 +478,7 @@ class DeviceBuilder {
// Any features and extensions that are requested/required in PhysicalDeviceSelector are automatically enabled. // Any features and extensions that are requested/required in PhysicalDeviceSelector are automatically enabled.
DeviceBuilder (PhysicalDevice physical_device); DeviceBuilder (PhysicalDevice physical_device);
detail::Expected<Device, detail::Error<DeviceError>> build () const; detail::Result<Device> build () const;
// For Advanced Users: specify the exact list of VkDeviceQueueCreateInfo's needed for the application. // For Advanced Users: specify the exact list of VkDeviceQueueCreateInfo's needed for the application.
// If a custom queue setup is provided, getting the queues and queue indexes is up to the application. // If a custom queue setup is provided, getting the queues and queue indexes is up to the application.
@ -511,11 +519,11 @@ struct Swapchain {
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
// Returns a vector of VkImage handles to the swapchain // Returns a vector of VkImage handles to the swapchain
detail::Expected<std::vector<VkImage>, detail::Error<SwapchainError>> get_images (); detail::Result<std::vector<VkImage>> get_images ();
// Returns a vector of VkImageView's to the VkImage's of the swapchain // Returns a vector of VkImageView's to the VkImage's of the swapchain
// VkImageViews must be destroyed // VkImageViews must be destroyed
detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>> get_image_views (); detail::Result<std::vector<VkImageView>> get_image_views ();
void destroy_image_views (std::vector<VkImageView> const& image_views); void destroy_image_views (std::vector<VkImageView> const& image_views);
}; };
@ -527,8 +535,8 @@ class SwapchainBuilder {
SwapchainBuilder (Device const& device, VkSurfaceKHR const surface); SwapchainBuilder (Device const& device, VkSurfaceKHR const surface);
SwapchainBuilder (VkPhysicalDevice const physical_device, VkDevice const device, VkSurfaceKHR const surface); SwapchainBuilder (VkPhysicalDevice const physical_device, VkDevice const device, VkSurfaceKHR const surface);
detail::Expected<Swapchain, detail::Error<SwapchainError>> build () const; detail::Result<Swapchain> build () const;
detail::Expected<Swapchain, detail::Error<SwapchainError>> recreate (Swapchain const& swapchain) const; detail::Result<Swapchain> recreate (Swapchain const& swapchain) const;
SwapchainBuilder& set_desired_extent (uint32_t width, uint32_t height); SwapchainBuilder& set_desired_extent (uint32_t width, uint32_t height);
@ -547,7 +555,7 @@ class SwapchainBuilder {
void add_desired_formats (std::vector<VkSurfaceFormatKHR>& formats) const; void add_desired_formats (std::vector<VkSurfaceFormatKHR>& formats) const;
void add_desired_present_modes (std::vector<VkPresentModeKHR>& modes) const; void add_desired_present_modes (std::vector<VkPresentModeKHR>& modes) const;
// for use in swapchain recreation // for use in swapchain recreation
detail::Expected<Swapchain, detail::Error<SwapchainError>> build (VkSwapchainKHR old_swapchain) const; detail::Result<Swapchain> build (VkSwapchainKHR old_swapchain) const;
struct SwapchainInfo { struct SwapchainInfo {
VkPhysicalDevice physical_device = VK_NULL_HANDLE; VkPhysicalDevice physical_device = VK_NULL_HANDLE;
@ -565,4 +573,13 @@ class SwapchainBuilder {
} info; } info;
}; };
} // namespace vkb } // namespace vkb
namespace std {
template <> struct is_error_code_enum<vkb::InstanceError> : true_type {};
template <> struct is_error_code_enum<vkb::PhysicalDeviceError> : true_type {};
template <> struct is_error_code_enum<vkb::QueueError> : true_type {};
template <> struct is_error_code_enum<vkb::DeviceError> : true_type {};
template <> struct is_error_code_enum<vkb::SwapchainError> : true_type {};
} // namespace std

View File

@ -1,4 +1,4 @@
add_executable(vk-bootstrap-test main.cpp run_tests.cpp) add_executable(vk-bootstrap-test main.cpp bootstrap_tests.cpp error_code_tests.cpp)
target_link_libraries(vk-bootstrap-test target_link_libraries(vk-bootstrap-test
PRIVATE PRIVATE
vk-bootstrap vk-bootstrap

View File

@ -8,7 +8,7 @@
// changing present modes and/or image formats // changing present modes and/or image formats
TEST_CASE ("Instance with surface") { TEST_CASE ("Instance with surface", "[VkBootstrap.bootstrap]") {
GIVEN ("A window and a vulkan instance") { GIVEN ("A window and a vulkan instance") {
auto window = create_window_glfw (); auto window = create_window_glfw ();
@ -54,7 +54,7 @@ TEST_CASE ("Instance with surface") {
} }
} }
TEST_CASE ("instance configuration") { TEST_CASE ("instance configuration", "[VkBootstrap.bootstrap]") {
SECTION ("custom debug callback") { SECTION ("custom debug callback") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
@ -97,7 +97,7 @@ TEST_CASE ("instance configuration") {
} }
} }
TEST_CASE ("Headless Vulkan") { TEST_CASE ("Headless Vulkan", "[VkBootstrap.bootstrap]") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = builder.request_validation_layers ().set_headless ().build (); auto instance_ret = builder.request_validation_layers ().set_headless ().build ();
@ -116,7 +116,7 @@ TEST_CASE ("Headless Vulkan") {
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance (instance_ret.value ());
} }
TEST_CASE ("Device Configuration") { TEST_CASE ("Device Configuration", "[VkBootstrap.bootstrap]") {
auto window = create_window_glfw (); auto window = create_window_glfw ();
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
@ -180,7 +180,7 @@ TEST_CASE ("Device Configuration") {
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance (instance_ret.value ());
} }
TEST_CASE ("Swapchain") { TEST_CASE ("Swapchain", "[VkBootstrap.bootstrap]") {
GIVEN ("A working instance, window, surface, and device") { GIVEN ("A working instance, window, surface, and device") {
auto window = create_window_glfw (); auto window = create_window_glfw ();
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
@ -268,7 +268,7 @@ void* VKAPI_PTR shim_vkReallocationFunction (
void VKAPI_PTR shim_vkFreeFunction (void* /*pUserData*/, void* pMemory) { return free (pMemory); } void VKAPI_PTR shim_vkFreeFunction (void* /*pUserData*/, void* pMemory) { return free (pMemory); }
TEST_CASE ("Allocation Callbacks") { TEST_CASE ("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
VkAllocationCallbacks allocation_callbacks{}; VkAllocationCallbacks allocation_callbacks{};
allocation_callbacks.pfnAllocation = &shim_vkAllocationFunction; allocation_callbacks.pfnAllocation = &shim_vkAllocationFunction;
allocation_callbacks.pfnReallocation = &shim_vkReallocationFunction; allocation_callbacks.pfnReallocation = &shim_vkReallocationFunction;
@ -296,7 +296,7 @@ TEST_CASE ("Allocation Callbacks") {
vkb::SwapchainBuilder swapchain_builder (device); vkb::SwapchainBuilder swapchain_builder (device);
auto swapchain_ret = swapchain_builder.set_allocation_callbacks (&allocation_callbacks).build (); auto swapchain_ret = swapchain_builder.set_allocation_callbacks (&allocation_callbacks).build ();
REQUIRE (swapchain_ret.has_value ()); REQUIRE (swapchain_ret.has_value ());
auto swapchain = swapchain_ret.value (); // auto swapchain = swapchain_ret.value ();
vkb::destroy_swapchain (swapchain_ret.value ()); vkb::destroy_swapchain (swapchain_ret.value ());
vkb::destroy_device (device_ret.value ()); vkb::destroy_device (device_ret.value ());

View File

@ -0,0 +1,98 @@
#include <catch2/catch.hpp>
#include "VkBootstrap.h"
TEST_CASE ("is_error_code_enum", "[VkBootstrap.error_code]") {
STATIC_REQUIRE (std::is_error_code_enum<vkb::InstanceError>::value);
STATIC_REQUIRE (std::is_error_code_enum<vkb::PhysicalDeviceError>::value);
STATIC_REQUIRE (std::is_error_code_enum<vkb::QueueError>::value);
STATIC_REQUIRE (std::is_error_code_enum<vkb::DeviceError>::value);
STATIC_REQUIRE (std::is_error_code_enum<vkb::SwapchainError>::value);
}
TEST_CASE ("make_error_code", "[VkBootstrap.error_code]") {
GIVEN ("An InstanceError") {
const auto error = vkb::InstanceError::vulkan_unavailable;
WHEN ("Creating an error code from it") {
std::error_code ec = make_error_code (error);
THEN ("The error code is equal to the original error") { REQUIRE (ec == error); }
THEN ("The error code is not equal to an unrelated error") {
REQUIRE (ec != vkb::InstanceError::failed_create_instance);
}
THEN ("We can get the error message") {
REQUIRE (ec.message () == "vulkan_unavailable");
}
}
}
GIVEN ("A PhysicalDeviceError") {
const auto error = vkb::PhysicalDeviceError::no_physical_devices_found;
WHEN ("Creating an error code from it") {
std::error_code ec = make_error_code (error);
THEN ("The error code is equal to the original error") { REQUIRE (ec == error); }
THEN ("The error code is not equal to an unrelated error") {
REQUIRE (ec != vkb::InstanceError::failed_create_instance);
}
THEN ("We can get the error message") {
REQUIRE (ec.message () == "no_physical_devices_found");
}
}
}
GIVEN ("A QueueError") {
const auto error = vkb::QueueError::invalid_queue_family_index;
WHEN ("Creating an error code from it") {
std::error_code ec = make_error_code (error);
THEN ("The error code is equal to the original error") { REQUIRE (ec == error); }
THEN ("The error code is not equal to an unrelated error") {
REQUIRE (ec != vkb::InstanceError::failed_create_instance);
}
THEN ("We can get the error message") {
REQUIRE (ec.message () == "invalid_queue_family_index");
}
}
}
GIVEN ("A DeviceError") {
const auto error = vkb::DeviceError::failed_create_device;
WHEN ("Creating an error code from it") {
std::error_code ec = make_error_code (error);
THEN ("The error code is equal to the original error") { REQUIRE (ec == error); }
THEN ("The error code is not equal to an unrelated error") {
REQUIRE (ec != vkb::InstanceError::failed_create_instance);
}
THEN ("We can get the error message") {
REQUIRE (ec.message () == "failed_create_device");
}
}
}
GIVEN ("A SwapchainError") {
const auto error = vkb::SwapchainError::failed_create_swapchain;
WHEN ("Creating an error code from it") {
std::error_code ec = make_error_code (error);
THEN ("The error code is equal to the original error") { REQUIRE (ec == error); }
THEN ("The error code is not equal to an unrelated error") {
REQUIRE (ec != vkb::InstanceError::failed_create_instance);
}
THEN ("We can get the error message") {
REQUIRE (ec.message () == "failed_create_swapchain");
}
}
}
}