mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-22 15:24:34 +00:00
Error handling with std::error_code
This commit is contained in:
parent
120a162264
commit
df53490ede
@ -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();
|
||||||
```
|
```
|
||||||
|
@ -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 ();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
@ -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
|
||||||
|
@ -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 ());
|
98
tests/error_code_tests.cpp
Normal file
98
tests/error_code_tests.cpp
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user