Move Result & Error out of the detail namespace

Since its a part of the public interface, it means applications using vk-bootstrap
will inevitably need to use the types in error handling paths.
This commit is contained in:
Charles Giessen 2022-10-07 11:04:56 -06:00 committed by Charles Giessen
parent 789a24edb7
commit ab52ad97a8
2 changed files with 86 additions and 89 deletions

View File

@ -469,14 +469,14 @@ const char* to_string(SwapchainError err) {
} }
} }
detail::Result<SystemInfo> SystemInfo::get_system_info() { Result<SystemInfo> SystemInfo::get_system_info() {
if (!detail::vulkan_functions().init_vulkan_funcs(nullptr)) { if (!detail::vulkan_functions().init_vulkan_funcs(nullptr)) {
return make_error_code(InstanceError::vulkan_unavailable); return make_error_code(InstanceError::vulkan_unavailable);
} }
return SystemInfo(); return SystemInfo();
} }
detail::Result<SystemInfo> SystemInfo::get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) { Result<SystemInfo> SystemInfo::get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr) {
// Using externally provided function pointers, assume the loader is available // Using externally provided function pointers, assume the loader is available
if (!detail::vulkan_functions().init_vulkan_funcs(fp_vkGetInstanceProcAddr)) { if (!detail::vulkan_functions().init_vulkan_funcs(fp_vkGetInstanceProcAddr)) {
return make_error_code(InstanceError::vulkan_unavailable); return make_error_code(InstanceError::vulkan_unavailable);
@ -554,7 +554,7 @@ InstanceBuilder::InstanceBuilder(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcA
} }
InstanceBuilder::InstanceBuilder() {} InstanceBuilder::InstanceBuilder() {}
detail::Result<Instance> InstanceBuilder::build() const { Result<Instance> InstanceBuilder::build() const {
auto sys_info_ret = SystemInfo::get_system_info(info.fp_vkGetInstanceProcAddr); auto sys_info_ret = SystemInfo::get_system_info(info.fp_vkGetInstanceProcAddr);
if (!sys_info_ret) return sys_info_ret.error(); if (!sys_info_ret) return sys_info_ret.error();
@ -719,7 +719,7 @@ detail::Result<Instance> InstanceBuilder::build() const {
Instance instance; Instance instance;
VkResult res = VkResult res =
detail::vulkan_functions().fp_vkCreateInstance(&instance_create_info, info.allocation_callbacks, &instance.instance); detail::vulkan_functions().fp_vkCreateInstance(&instance_create_info, info.allocation_callbacks, &instance.instance);
if (res != VK_SUCCESS) return detail::Result<Instance>(InstanceError::failed_create_instance, res); if (res != VK_SUCCESS) return Result<Instance>(InstanceError::failed_create_instance, res);
detail::vulkan_functions().init_instance_funcs(instance.instance); detail::vulkan_functions().init_instance_funcs(instance.instance);
@ -732,7 +732,7 @@ detail::Result<Instance> InstanceBuilder::build() const {
&instance.debug_messenger, &instance.debug_messenger,
info.allocation_callbacks); info.allocation_callbacks);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return detail::Result<Instance>(InstanceError::failed_create_debug_messenger, res); return Result<Instance>(InstanceError::failed_create_debug_messenger, res);
} }
} }
@ -1162,7 +1162,7 @@ PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance, VkSurfa
criteria.desired_version = instance.api_version; criteria.desired_version = instance.api_version;
} }
detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(DeviceSelectionMode selection) const { Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(DeviceSelectionMode selection) const {
#if !defined(NDEBUG) #if !defined(NDEBUG)
// Validation // Validation
for (const auto& node : criteria.extended_features_chain) { for (const auto& node : criteria.extended_features_chain) {
@ -1177,7 +1177,7 @@ detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(
if (criteria.require_present && !criteria.defer_surface_initialization) { if (criteria.require_present && !criteria.defer_surface_initialization) {
if (instance_info.surface == VK_NULL_HANDLE) if (instance_info.surface == VK_NULL_HANDLE)
return detail::Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_surface_provided }; return Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_surface_provided };
} }
// Get the VkPhysicalDevice handles on the system // Get the VkPhysicalDevice handles on the system
@ -1186,11 +1186,10 @@ detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(
auto vk_physical_devices_ret = detail::get_vector<VkPhysicalDevice>( auto vk_physical_devices_ret = detail::get_vector<VkPhysicalDevice>(
vk_physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, instance_info.instance); vk_physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, instance_info.instance);
if (vk_physical_devices_ret != VK_SUCCESS) { if (vk_physical_devices_ret != VK_SUCCESS) {
return detail::Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::failed_enumerate_physical_devices, return Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::failed_enumerate_physical_devices, vk_physical_devices_ret };
vk_physical_devices_ret };
} }
if (vk_physical_devices.size() == 0) { if (vk_physical_devices.size() == 0) {
return detail::Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_physical_devices_found }; return Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_physical_devices_found };
} }
auto fill_out_phys_dev_with_criteria = [&](PhysicalDevice& phys_dev) { auto fill_out_phys_dev_with_criteria = [&](PhysicalDevice& phys_dev) {
@ -1248,32 +1247,32 @@ detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(
return physical_devices; return physical_devices;
} }
detail::Result<PhysicalDevice> PhysicalDeviceSelector::select(DeviceSelectionMode selection) const { Result<PhysicalDevice> PhysicalDeviceSelector::select(DeviceSelectionMode selection) const {
auto const selected_devices = select_impl(selection); auto const selected_devices = select_impl(selection);
if (!selected_devices) return detail::Result<PhysicalDevice>{ selected_devices.error() }; if (!selected_devices) return Result<PhysicalDevice>{ selected_devices.error() };
if (selected_devices.value().size() == 0) { if (selected_devices.value().size() == 0) {
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_suitable_device }; return Result<PhysicalDevice>{ PhysicalDeviceError::no_suitable_device };
} }
return selected_devices.value().at(0); return selected_devices.value().at(0);
} }
// Return all devices which are considered suitable - intended for applications which want to let the user pick the physical device // Return all devices which are considered suitable - intended for applications which want to let the user pick the physical device
detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_devices(DeviceSelectionMode selection) const { Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_devices(DeviceSelectionMode selection) const {
auto const selected_devices = select_impl(selection); auto const selected_devices = select_impl(selection);
if (!selected_devices) return detail::Result<std::vector<PhysicalDevice>>{ selected_devices.error() }; if (!selected_devices) return Result<std::vector<PhysicalDevice>>{ selected_devices.error() };
if (selected_devices.value().size() == 0) { if (selected_devices.value().size() == 0) {
return detail::Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_suitable_device }; return Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_suitable_device };
} }
return selected_devices.value(); return selected_devices.value();
} }
detail::Result<std::vector<std::string>> PhysicalDeviceSelector::select_device_names(DeviceSelectionMode selection) const { Result<std::vector<std::string>> PhysicalDeviceSelector::select_device_names(DeviceSelectionMode selection) const {
auto const selected_devices = select_impl(selection); auto const selected_devices = select_impl(selection);
if (!selected_devices) return detail::Result<std::vector<std::string>>{ selected_devices.error() }; if (!selected_devices) return Result<std::vector<std::string>>{ selected_devices.error() };
if (selected_devices.value().size() == 0) { if (selected_devices.value().size() == 0) {
return detail::Result<std::vector<std::string>>{ PhysicalDeviceError::no_suitable_device }; return Result<std::vector<std::string>>{ PhysicalDeviceError::no_suitable_device };
} }
std::vector<std::string> names; std::vector<std::string> names;
for (const auto& pd : selected_devices.value()) { for (const auto& pd : selected_devices.value()) {
@ -1410,61 +1409,55 @@ PhysicalDevice::operator VkPhysicalDevice() const { return this->physical_device
// ---- Queues ---- // // ---- Queues ---- //
detail::Result<uint32_t> Device::get_queue_index(QueueType type) const { Result<uint32_t> Device::get_queue_index(QueueType type) const {
uint32_t index = detail::QUEUE_INDEX_MAX_VALUE; uint32_t index = detail::QUEUE_INDEX_MAX_VALUE;
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 == detail::QUEUE_INDEX_MAX_VALUE) if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::present_unavailable };
return detail::Result<uint32_t>{ QueueError::present_unavailable };
break; break;
case QueueType::graphics: case QueueType::graphics:
index = detail::get_first_queue_index(queue_families, VK_QUEUE_GRAPHICS_BIT); index = detail::get_first_queue_index(queue_families, VK_QUEUE_GRAPHICS_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE) if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::graphics_unavailable };
return detail::Result<uint32_t>{ QueueError::graphics_unavailable };
break; break;
case QueueType::compute: case QueueType::compute:
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT); index = detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE) if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::compute_unavailable };
return detail::Result<uint32_t>{ QueueError::compute_unavailable };
break; break;
case QueueType::transfer: case QueueType::transfer:
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT); index = detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE) if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::transfer_unavailable };
return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
break; break;
default: default:
return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index }; return Result<uint32_t>{ QueueError::invalid_queue_family_index };
} }
return index; return index;
} }
detail::Result<uint32_t> Device::get_dedicated_queue_index(QueueType type) const { Result<uint32_t> Device::get_dedicated_queue_index(QueueType type) const {
uint32_t index = detail::QUEUE_INDEX_MAX_VALUE; uint32_t index = detail::QUEUE_INDEX_MAX_VALUE;
switch (type) { switch (type) {
case QueueType::compute: case QueueType::compute:
index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT); index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE) if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::compute_unavailable };
return detail::Result<uint32_t>{ QueueError::compute_unavailable };
break; break;
case QueueType::transfer: case QueueType::transfer:
index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT); index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE) if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::transfer_unavailable };
return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
break; break;
default: default:
return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index }; return Result<uint32_t>{ QueueError::invalid_queue_family_index };
} }
return index; return index;
} }
detail::Result<VkQueue> Device::get_queue(QueueType type) const { 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() };
VkQueue out_queue; VkQueue out_queue;
internal_table.fp_vkGetDeviceQueue(device, index.value(), 0, &out_queue); internal_table.fp_vkGetDeviceQueue(device, index.value(), 0, &out_queue);
return out_queue; return out_queue;
} }
detail::Result<VkQueue> Device::get_dedicated_queue(QueueType type) const { 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() };
VkQueue out_queue; VkQueue out_queue;
@ -1491,7 +1484,7 @@ void destroy_device(Device device) {
DeviceBuilder::DeviceBuilder(PhysicalDevice phys_device) { physical_device = phys_device; } DeviceBuilder::DeviceBuilder(PhysicalDevice phys_device) { physical_device = phys_device; }
detail::Result<Device> DeviceBuilder::build() const { Result<Device> DeviceBuilder::build() const {
std::vector<CustomQueueDescription> queue_descriptions; std::vector<CustomQueueDescription> queue_descriptions;
queue_descriptions.insert(queue_descriptions.end(), info.queue_descriptions.begin(), info.queue_descriptions.end()); queue_descriptions.insert(queue_descriptions.end(), info.queue_descriptions.begin(), info.queue_descriptions.end());
@ -1760,9 +1753,9 @@ SwapchainBuilder::SwapchainBuilder(VkPhysicalDevice const physical_device,
info.present_queue_index = detail::get_present_queue_index(physical_device, surface, queue_families); info.present_queue_index = detail::get_present_queue_index(physical_device, surface, queue_families);
} }
} }
detail::Result<Swapchain> SwapchainBuilder::build() const { Result<Swapchain> SwapchainBuilder::build() const {
if (info.surface == VK_NULL_HANDLE) { if (info.surface == VK_NULL_HANDLE) {
return detail::Error{ SwapchainError::surface_handle_not_provided }; return Error{ SwapchainError::surface_handle_not_provided };
} }
auto desired_formats = info.desired_formats; auto desired_formats = info.desired_formats;
@ -1772,7 +1765,7 @@ detail::Result<Swapchain> SwapchainBuilder::build() const {
auto surface_support_ret = detail::query_surface_support_details(info.physical_device, info.surface); auto surface_support_ret = detail::query_surface_support_details(info.physical_device, info.surface);
if (!surface_support_ret.has_value()) if (!surface_support_ret.has_value())
return detail::Error{ SwapchainError::failed_query_surface_support_details, surface_support_ret.vk_result() }; return Error{ SwapchainError::failed_query_surface_support_details, surface_support_ret.vk_result() };
auto surface_support = surface_support_ret.value(); auto surface_support = surface_support_ret.value();
uint32_t image_count = info.min_image_count; uint32_t image_count = info.min_image_count;
@ -1848,7 +1841,7 @@ detail::Result<Swapchain> SwapchainBuilder::build() const {
auto res = swapchain_create_proc(info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain); auto res = swapchain_create_proc(info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return detail::Error{ SwapchainError::failed_create_swapchain, res }; return 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;
@ -1862,7 +1855,7 @@ detail::Result<Swapchain> SwapchainBuilder::build() const {
info.device, swapchain.internal_table.fp_vkDestroySwapchainKHR, "vkDestroySwapchainKHR"); info.device, swapchain.internal_table.fp_vkDestroySwapchainKHR, "vkDestroySwapchainKHR");
auto images = swapchain.get_images(); auto images = swapchain.get_images();
if (!images) { if (!images) {
return detail::Error{ SwapchainError::failed_get_swapchain_images }; return Error{ SwapchainError::failed_get_swapchain_images };
} }
swapchain.requested_min_image_count = image_count; swapchain.requested_min_image_count = image_count;
swapchain.present_mode = present_mode; swapchain.present_mode = present_mode;
@ -1870,18 +1863,18 @@ detail::Result<Swapchain> SwapchainBuilder::build() const {
swapchain.allocation_callbacks = info.allocation_callbacks; swapchain.allocation_callbacks = info.allocation_callbacks;
return swapchain; return swapchain;
} }
detail::Result<std::vector<VkImage>> Swapchain::get_images() { Result<std::vector<VkImage>> Swapchain::get_images() {
std::vector<VkImage> swapchain_images; std::vector<VkImage> swapchain_images;
auto swapchain_images_ret = auto swapchain_images_ret =
detail::get_vector<VkImage>(swapchain_images, internal_table.fp_vkGetSwapchainImagesKHR, device, swapchain); detail::get_vector<VkImage>(swapchain_images, internal_table.fp_vkGetSwapchainImagesKHR, device, swapchain);
if (swapchain_images_ret != VK_SUCCESS) { if (swapchain_images_ret != VK_SUCCESS) {
return detail::Error{ SwapchainError::failed_get_swapchain_images, swapchain_images_ret }; return Error{ SwapchainError::failed_get_swapchain_images, swapchain_images_ret };
} }
return swapchain_images; return swapchain_images;
} }
detail::Result<std::vector<VkImageView>> Swapchain::get_image_views() { return get_image_views(nullptr); } Result<std::vector<VkImageView>> Swapchain::get_image_views() { return get_image_views(nullptr); }
detail::Result<std::vector<VkImageView>> Swapchain::get_image_views(const void* pNext) { Result<std::vector<VkImageView>> Swapchain::get_image_views(const void* pNext) {
const auto swapchain_images_ret = get_images(); const auto swapchain_images_ret = get_images();
if (!swapchain_images_ret) return swapchain_images_ret.error(); if (!swapchain_images_ret) return swapchain_images_ret.error();
const auto swapchain_images = swapchain_images_ret.value(); const auto swapchain_images = swapchain_images_ret.value();
@ -1904,9 +1897,8 @@ detail::Result<std::vector<VkImageView>> Swapchain::get_image_views(const void*
createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1; createInfo.subresourceRange.layerCount = 1;
VkResult res = internal_table.fp_vkCreateImageView(device, &createInfo, allocation_callbacks, &views[i]); VkResult res = internal_table.fp_vkCreateImageView(device, &createInfo, allocation_callbacks, &views[i]);
if (res != VK_SUCCESS) return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res }; if (res != VK_SUCCESS) return Error{ SwapchainError::failed_create_swapchain_image_views, res };
} }
return views; return views;
} }

View File

@ -52,8 +52,6 @@
namespace vkb { namespace vkb {
namespace detail {
struct Error { struct Error {
std::error_code type; std::error_code type;
VkResult vk_result = VK_SUCCESS; // optional error value if a vulkan call failed VkResult vk_result = VK_SUCCESS; // optional error value if a vulkan call failed
@ -61,75 +59,76 @@ struct Error {
template <typename T> class Result { template <typename T> class Result {
public: public:
Result(const T& value) : m_value{ value }, m_init{ true } {} Result(const T& value) noexcept : m_value{ value }, m_init{ true } {}
Result(T&& value) : m_value{ std::move(value) }, m_init{ true } {} Result(T&& value) noexcept : m_value{ std::move(value) }, m_init{ true } {}
Result(Error error) : m_error{ error }, m_init{ false } {} Result(Error error) noexcept : m_error{ error }, m_init{ false } {}
Result(std::error_code error_code, VkResult result = VK_SUCCESS) : m_error{ error_code, result }, m_init{ false } {} Result(std::error_code error_code, VkResult result = VK_SUCCESS) noexcept
: m_error{ error_code, result }, m_init{ false } {}
~Result() { destroy(); } ~Result() noexcept { destroy(); }
Result(Result const& expected) : m_init(expected.m_init) { Result(Result const& expected) noexcept : m_init(expected.m_init) {
if (m_init) if (m_init)
new (&m_value) T{ expected.m_value }; new (&m_value) T{ expected.m_value };
else else
m_error = expected.m_error; m_error = expected.m_error;
} }
Result& operator=(Result const& result) { Result& operator=(Result const& result) noexcept {
m_init = result.m_init; m_init = result.m_init;
if (m_init) if (m_init)
new (&m_value) T{ result.m_value }; new (&m_value) T{ result.m_value };
else else
m_error = result.m_error; m_error = result.m_error;
} }
Result(Result&& expected) : m_init(expected.m_init) { Result(Result&& expected) noexcept : m_init(expected.m_init) {
if (m_init) if (m_init)
new (&m_value) T{ std::move(expected.m_value) }; new (&m_value) T{ std::move(expected.m_value) };
else else
m_error = std::move(expected.m_error); m_error = std::move(expected.m_error);
expected.destroy(); expected.destroy();
} }
Result& operator=(Result&& result) { Result& operator=(Result&& result) noexcept {
m_init = result.m_init; m_init = result.m_init;
if (m_init) if (m_init)
new (&m_value) T{ std::move(result.m_value) }; new (&m_value) T{ std::move(result.m_value) };
else else
m_error = std::move(result.m_error); m_error = std::move(result.m_error);
} }
Result& operator=(const T& expect) { Result& operator=(const T& expect) noexcept {
destroy(); destroy();
m_init = true; m_init = true;
new (&m_value) T{ expect }; new (&m_value) T{ expect };
return *this; return *this;
} }
Result& operator=(T&& expect) { Result& operator=(T&& expect) noexcept {
destroy(); destroy();
m_init = true; m_init = true;
new (&m_value) T{ std::move(expect) }; new (&m_value) T{ std::move(expect) };
return *this; return *this;
} }
Result& operator=(const Error& error) { Result& operator=(const Error& error) noexcept {
destroy(); destroy();
m_init = false; m_init = false;
m_error = error; m_error = error;
return *this; return *this;
} }
Result& operator=(Error&& error) { Result& operator=(Error&& error) noexcept {
destroy(); destroy();
m_init = false; m_init = false;
m_error = error; m_error = error;
return *this; return *this;
} }
// clang-format off // clang-format off
const T* operator-> () const { assert (m_init); return &m_value; } const T* operator-> () const noexcept { assert (m_init); return &m_value; }
T* operator-> () { assert (m_init); return &m_value; } T* operator-> () noexcept { assert (m_init); return &m_value; }
const T& operator* () const& { assert (m_init); return m_value; } const T& operator* () const& noexcept { assert (m_init); return m_value; }
T& operator* () & { assert (m_init); return m_value; } T& operator* () & noexcept { assert (m_init); return m_value; }
T&& operator* () && { assert (m_init); return std::move (m_value); } T&& operator* () && noexcept { assert (m_init); return std::move (m_value); }
const T& value () const& { assert (m_init); return m_value; } const T& value () const& noexcept { assert (m_init); return m_value; }
T& value () & { assert (m_init); return m_value; } T& value () & noexcept { assert (m_init); return m_value; }
const T&& value () const&& { assert (m_init); return std::move (m_value); } const T&& value () const&& noexcept { assert (m_init); return std::move (m_value); }
T&& value () && { assert (m_init); return std::move (m_value); } T&& value () && noexcept { assert (m_init); return std::move (m_value); }
// std::error_code associated with the error // std::error_code associated with the error
std::error_code error() const { assert (!m_init); return m_error.type; } std::error_code error() const { assert (!m_init); return m_error.type; }
@ -139,6 +138,11 @@ template <typename T> class Result {
Error full_error() const { assert (!m_init); return m_error; } Error full_error() const { assert (!m_init); return m_error; }
// clang-format on // clang-format on
// check if the result has an error that matches a specific error case
template <typename E> bool matches_error(E error_enum_value) const {
return !m_init && static_cast<E>(m_error.type.value()) == error_enum_value;
}
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; }
@ -153,6 +157,7 @@ template <typename T> class Result {
bool m_init; bool m_init;
}; };
namespace detail {
struct GenericFeaturesPNextNode { struct GenericFeaturesPNextNode {
static const uint32_t field_capacity = 256; static const uint32_t field_capacity = 256;
@ -234,8 +239,8 @@ struct SystemInfo {
public: public:
// Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail. // Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail.
static detail::Result<SystemInfo> get_system_info(); static Result<SystemInfo> get_system_info();
static detail::Result<SystemInfo> get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr); static Result<SystemInfo> get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
// Returns true if a layer is available // Returns true if a layer is available
bool is_layer_available(const char* layer_name) const; bool is_layer_available(const char* layer_name) const;
@ -321,7 +326,7 @@ class InstanceBuilder {
explicit InstanceBuilder(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr); explicit InstanceBuilder(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
// Create a VkInstance. Return an error if it failed. // Create a VkInstance. Return an error if it failed.
detail::Result<Instance> build() const; 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);
@ -526,14 +531,14 @@ class PhysicalDeviceSelector {
// Return the first device which is suitable // Return the first device which is suitable
// use the `selection` parameter to configure if partially // use the `selection` parameter to configure if partially
detail::Result<PhysicalDevice> select(DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const; Result<PhysicalDevice> select(DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const;
// Return all devices which are considered suitable - intended for applications which want to let the user pick the physical device // Return all devices which are considered suitable - intended for applications which want to let the user pick the physical device
detail::Result<std::vector<PhysicalDevice>> select_devices( Result<std::vector<PhysicalDevice>> select_devices(
DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const; DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const;
// Return the names of all devices which are considered suitable - intended for applications which want to let the user pick the physical device // Return the names of all devices which are considered suitable - intended for applications which want to let the user pick the physical device
detail::Result<std::vector<std::string>> select_device_names( Result<std::vector<std::string>> select_device_names(
DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const; DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const;
// Set the surface in which the physical device should render to. // Set the surface in which the physical device should render to.
@ -661,7 +666,7 @@ class PhysicalDeviceSelector {
PhysicalDevice::Suitable is_device_suitable(PhysicalDevice const& phys_device) const; PhysicalDevice::Suitable is_device_suitable(PhysicalDevice const& phys_device) const;
detail::Result<std::vector<PhysicalDevice>> select_impl(DeviceSelectionMode selection) const; Result<std::vector<PhysicalDevice>> select_impl(DeviceSelectionMode selection) const;
}; };
// ---- Queue ---- // // ---- Queue ---- //
@ -682,13 +687,13 @@ struct Device {
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr; PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr;
detail::Result<uint32_t> get_queue_index(QueueType type) const; 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::Result<uint32_t> get_dedicated_queue_index(QueueType type) const; Result<uint32_t> get_dedicated_queue_index(QueueType type) const;
detail::Result<VkQueue> get_queue(QueueType type) const; 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::Result<VkQueue> get_dedicated_queue(QueueType type) const; Result<VkQueue> get_dedicated_queue(QueueType type) const;
// Return a loaded dispatch table // Return a loaded dispatch table
DispatchTable make_table() const; DispatchTable make_table() const;
@ -721,7 +726,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.
explicit DeviceBuilder(PhysicalDevice physical_device); explicit DeviceBuilder(PhysicalDevice physical_device);
detail::Result<Device> build() const; 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.
@ -760,13 +765,13 @@ 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::Result<std::vector<VkImage>> get_images(); 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. The pNext chain must be a nullptr or a valid // VkImageViews must be destroyed. The pNext chain must be a nullptr or a valid
// structure. // structure.
detail::Result<std::vector<VkImageView>> get_image_views(); Result<std::vector<VkImageView>> get_image_views();
detail::Result<std::vector<VkImageView>> get_image_views(const void* pNext); Result<std::vector<VkImageView>> get_image_views(const void* pNext);
void destroy_image_views(std::vector<VkImageView> const& image_views); void destroy_image_views(std::vector<VkImageView> const& image_views);
// A conversion function which allows this Swapchain to be used // A conversion function which allows this Swapchain to be used
@ -801,7 +806,7 @@ class SwapchainBuilder {
uint32_t graphics_queue_index = detail::QUEUE_INDEX_MAX_VALUE, uint32_t graphics_queue_index = detail::QUEUE_INDEX_MAX_VALUE,
uint32_t present_queue_index = detail::QUEUE_INDEX_MAX_VALUE); uint32_t present_queue_index = detail::QUEUE_INDEX_MAX_VALUE);
detail::Result<Swapchain> build() const; Result<Swapchain> build() const;
// Set the oldSwapchain member of VkSwapchainCreateInfoKHR. // Set the oldSwapchain member of VkSwapchainCreateInfoKHR.
// For use in rebuilding a swapchain. // For use in rebuilding a swapchain.