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)) {
return make_error_code(InstanceError::vulkan_unavailable);
}
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
if (!detail::vulkan_functions().init_vulkan_funcs(fp_vkGetInstanceProcAddr)) {
return make_error_code(InstanceError::vulkan_unavailable);
@ -554,7 +554,7 @@ InstanceBuilder::InstanceBuilder(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcA
}
InstanceBuilder::InstanceBuilder() {}
detail::Result<Instance> InstanceBuilder::build() const {
Result<Instance> InstanceBuilder::build() const {
auto sys_info_ret = SystemInfo::get_system_info(info.fp_vkGetInstanceProcAddr);
if (!sys_info_ret) return sys_info_ret.error();
@ -719,7 +719,7 @@ detail::Result<Instance> InstanceBuilder::build() const {
Instance instance;
VkResult res =
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);
@ -732,7 +732,7 @@ detail::Result<Instance> InstanceBuilder::build() const {
&instance.debug_messenger,
info.allocation_callbacks);
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;
}
detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(DeviceSelectionMode selection) const {
Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(DeviceSelectionMode selection) const {
#if !defined(NDEBUG)
// Validation
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 (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
@ -1186,11 +1186,10 @@ detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(
auto vk_physical_devices_ret = detail::get_vector<VkPhysicalDevice>(
vk_physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, instance_info.instance);
if (vk_physical_devices_ret != VK_SUCCESS) {
return detail::Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::failed_enumerate_physical_devices,
vk_physical_devices_ret };
return Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::failed_enumerate_physical_devices, vk_physical_devices_ret };
}
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) {
@ -1248,32 +1247,32 @@ detail::Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl(
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);
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) {
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_suitable_device };
return Result<PhysicalDevice>{ PhysicalDeviceError::no_suitable_device };
}
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
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);
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) {
return detail::Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_suitable_device };
return Result<std::vector<PhysicalDevice>>{ PhysicalDeviceError::no_suitable_device };
}
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);
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) {
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;
for (const auto& pd : selected_devices.value()) {
@ -1410,61 +1409,55 @@ PhysicalDevice::operator VkPhysicalDevice() const { return this->physical_device
// ---- 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;
switch (type) {
case QueueType::present:
index = detail::get_present_queue_index(physical_device.physical_device, surface, queue_families);
if (index == detail::QUEUE_INDEX_MAX_VALUE)
return detail::Result<uint32_t>{ QueueError::present_unavailable };
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::present_unavailable };
break;
case QueueType::graphics:
index = detail::get_first_queue_index(queue_families, VK_QUEUE_GRAPHICS_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE)
return detail::Result<uint32_t>{ QueueError::graphics_unavailable };
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::graphics_unavailable };
break;
case QueueType::compute:
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE)
return detail::Result<uint32_t>{ QueueError::compute_unavailable };
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::compute_unavailable };
break;
case QueueType::transfer:
index = detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE)
return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::transfer_unavailable };
break;
default:
return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index };
return Result<uint32_t>{ QueueError::invalid_queue_family_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;
switch (type) {
case QueueType::compute:
index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE)
return detail::Result<uint32_t>{ QueueError::compute_unavailable };
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::compute_unavailable };
break;
case QueueType::transfer:
index = detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT);
if (index == detail::QUEUE_INDEX_MAX_VALUE)
return detail::Result<uint32_t>{ QueueError::transfer_unavailable };
if (index == detail::QUEUE_INDEX_MAX_VALUE) return Result<uint32_t>{ QueueError::transfer_unavailable };
break;
default:
return detail::Result<uint32_t>{ QueueError::invalid_queue_family_index };
return Result<uint32_t>{ QueueError::invalid_queue_family_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);
if (!index.has_value()) return { index.error() };
VkQueue out_queue;
internal_table.fp_vkGetDeviceQueue(device, index.value(), 0, &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);
if (!index.has_value()) return { index.error() };
VkQueue out_queue;
@ -1491,7 +1484,7 @@ void destroy_device(Device 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;
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);
}
}
detail::Result<Swapchain> SwapchainBuilder::build() const {
Result<Swapchain> SwapchainBuilder::build() const {
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;
@ -1772,7 +1765,7 @@ detail::Result<Swapchain> SwapchainBuilder::build() const {
auto surface_support_ret = detail::query_surface_support_details(info.physical_device, info.surface);
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();
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);
if (res != VK_SUCCESS) {
return detail::Error{ SwapchainError::failed_create_swapchain, res };
return Error{ SwapchainError::failed_create_swapchain, res };
}
swapchain.device = info.device;
swapchain.image_format = surface_format.format;
@ -1862,7 +1855,7 @@ detail::Result<Swapchain> SwapchainBuilder::build() const {
info.device, swapchain.internal_table.fp_vkDestroySwapchainKHR, "vkDestroySwapchainKHR");
auto images = swapchain.get_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.present_mode = present_mode;
@ -1870,18 +1863,18 @@ detail::Result<Swapchain> SwapchainBuilder::build() const {
swapchain.allocation_callbacks = info.allocation_callbacks;
return swapchain;
}
detail::Result<std::vector<VkImage>> Swapchain::get_images() {
Result<std::vector<VkImage>> Swapchain::get_images() {
std::vector<VkImage> swapchain_images;
auto swapchain_images_ret =
detail::get_vector<VkImage>(swapchain_images, internal_table.fp_vkGetSwapchainImagesKHR, device, swapchain);
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;
}
detail::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() { return get_image_views(nullptr); }
Result<std::vector<VkImageView>> Swapchain::get_image_views(const void* pNext) {
const auto swapchain_images_ret = get_images();
if (!swapchain_images_ret) return swapchain_images_ret.error();
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.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;
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;
}

View File

@ -52,8 +52,6 @@
namespace vkb {
namespace detail {
struct Error {
std::error_code type;
VkResult vk_result = VK_SUCCESS; // optional error value if a vulkan call failed
@ -61,75 +59,76 @@ struct Error {
template <typename T> class Result {
public:
Result(const T& value) : m_value{ value }, m_init{ true } {}
Result(T&& value) : m_value{ std::move(value) }, m_init{ true } {}
Result(const T& value) noexcept : m_value{ 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(Result const& expected) : m_init(expected.m_init) {
~Result() noexcept { destroy(); }
Result(Result const& expected) noexcept : m_init(expected.m_init) {
if (m_init)
new (&m_value) T{ expected.m_value };
else
m_error = expected.m_error;
}
Result& operator=(Result const& result) {
Result& operator=(Result const& result) noexcept {
m_init = result.m_init;
if (m_init)
new (&m_value) T{ result.m_value };
else
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)
new (&m_value) T{ std::move(expected.m_value) };
else
m_error = std::move(expected.m_error);
expected.destroy();
}
Result& operator=(Result&& result) {
Result& operator=(Result&& result) noexcept {
m_init = result.m_init;
if (m_init)
new (&m_value) T{ std::move(result.m_value) };
else
m_error = std::move(result.m_error);
}
Result& operator=(const T& expect) {
Result& operator=(const T& expect) noexcept {
destroy();
m_init = true;
new (&m_value) T{ expect };
return *this;
}
Result& operator=(T&& expect) {
Result& operator=(T&& expect) noexcept {
destroy();
m_init = true;
new (&m_value) T{ std::move(expect) };
return *this;
}
Result& operator=(const Error& error) {
Result& operator=(const Error& error) noexcept {
destroy();
m_init = false;
m_error = error;
return *this;
}
Result& operator=(Error&& error) {
Result& operator=(Error&& error) noexcept {
destroy();
m_init = false;
m_error = error;
return *this;
}
// clang-format off
const T* operator-> () const { assert (m_init); return &m_value; }
T* operator-> () { assert (m_init); return &m_value; }
const T& operator* () const& { assert (m_init); return m_value; }
T& operator* () & { assert (m_init); return m_value; }
T&& operator* () && { assert (m_init); return std::move (m_value); }
const T& value () const& { assert (m_init); return m_value; }
T& value () & { assert (m_init); return m_value; }
const T&& value () const&& { assert (m_init); return std::move (m_value); }
T&& value () && { assert (m_init); return std::move (m_value); }
const T* operator-> () const noexcept { assert (m_init); return &m_value; }
T* operator-> () noexcept { assert (m_init); return &m_value; }
const T& operator* () const& noexcept { assert (m_init); return m_value; }
T& operator* () & noexcept { assert (m_init); return m_value; }
T&& operator* () && noexcept { assert (m_init); return std::move (m_value); }
const T& value () const& noexcept { assert (m_init); return m_value; }
T& value () & noexcept { assert (m_init); return m_value; }
const T&& value () const&& noexcept { 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 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; }
// 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; }
explicit operator bool() const { return m_init; }
@ -153,6 +157,7 @@ template <typename T> class Result {
bool m_init;
};
namespace detail {
struct GenericFeaturesPNextNode {
static const uint32_t field_capacity = 256;
@ -234,8 +239,8 @@ struct SystemInfo {
public:
// Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail.
static detail::Result<SystemInfo> get_system_info();
static detail::Result<SystemInfo> get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
static Result<SystemInfo> get_system_info();
static Result<SystemInfo> get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
// Returns true if a layer is available
bool is_layer_available(const char* layer_name) const;
@ -321,7 +326,7 @@ class InstanceBuilder {
explicit InstanceBuilder(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
// 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.
InstanceBuilder& set_app_name(const char* app_name);
@ -526,14 +531,14 @@ class PhysicalDeviceSelector {
// Return the first device which is suitable
// 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
detail::Result<std::vector<PhysicalDevice>> select_devices(
Result<std::vector<PhysicalDevice>> select_devices(
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
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;
// 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;
detail::Result<std::vector<PhysicalDevice>> select_impl(DeviceSelectionMode selection) const;
Result<std::vector<PhysicalDevice>> select_impl(DeviceSelectionMode selection) const;
};
// ---- Queue ---- //
@ -682,13 +687,13 @@ struct Device {
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
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
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
detail::Result<VkQueue> get_dedicated_queue(QueueType type) const;
Result<VkQueue> get_dedicated_queue(QueueType type) const;
// Return a loaded dispatch table
DispatchTable make_table() const;
@ -721,7 +726,7 @@ class DeviceBuilder {
// Any features and extensions that are requested/required in PhysicalDeviceSelector are automatically enabled.
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.
// 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;
// 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.
// VkImageViews must be destroyed. The pNext chain must be a nullptr or a valid
// structure.
detail::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();
Result<std::vector<VkImageView>> get_image_views(const void* pNext);
void destroy_image_views(std::vector<VkImageView> const& image_views);
// 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 present_queue_index = detail::QUEUE_INDEX_MAX_VALUE);
detail::Result<Swapchain> build() const;
Result<Swapchain> build() const;
// Set the oldSwapchain member of VkSwapchainCreateInfoKHR.
// For use in rebuilding a swapchain.