From 3e7e283e3f417ede4d9e2101b90adc841236ec64 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Mon, 10 Feb 2020 11:29:09 -0700 Subject: [PATCH] Revised error handling to be sensible and consistent. While more error values need to be fleshed out (one for every possible vulkan error) it has all of the major issues handled. --- example/triangle.cpp | 141 +++++++++++++++-------------------------- src/VkBootstrap.cpp | 146 ++++++++++++++++++++++++++++--------------- src/VkBootstrap.h | 110 +++++++++++++++++++++----------- tests/run_tests.cpp | 37 ++++------- 4 files changed, 232 insertions(+), 202 deletions(-) diff --git a/example/triangle.cpp b/example/triangle.cpp index e6c9e7f..34e4c02 100644 --- a/example/triangle.cpp +++ b/example/triangle.cpp @@ -8,8 +8,7 @@ const int MAX_FRAMES_IN_FLIGHT = 2; -struct Init -{ +struct Init { GLFWwindow* window; vkb::Instance instance; VkSurfaceKHR surface; @@ -17,8 +16,7 @@ struct Init vkb::Swapchain swapchain; }; -struct RenderData -{ +struct RenderData { VkQueue graphics_queue; VkQueue present_queue; @@ -40,15 +38,13 @@ struct RenderData size_t current_frame = 0; }; -int device_initialization (Init& init) -{ +int device_initialization (Init& init) { init.window = create_window_glfw (false); vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.set_default_debug_messenger ().setup_validation_layers ().build (); - if (!instance_ret) - { - std::cout << instance_ret.error ().msg << "\n"; + if (!instance_ret) { + std::cout << static_cast (instance_ret.error ().type) << "\n"; } init.instance = instance_ret.value (); @@ -56,40 +52,35 @@ int device_initialization (Init& init) vkb::PhysicalDeviceSelector phys_device_selector (init.instance); auto phys_device_ret = phys_device_selector.set_surface (init.surface).select (); - if (!phys_device_ret) - { - std::cout << phys_device_ret.error ().msg << "\n"; + if (!phys_device_ret) { + std::cout << static_cast (phys_device_ret.error ().type) << "\n"; } vkb::PhysicalDevice physical_device = phys_device_ret.value (); vkb::DeviceBuilder device_builder{ physical_device }; auto device_ret = device_builder.build (); - if (!device_ret) - { - std::cout << device_ret.error ().msg << "\n"; + if (!device_ret) { + std::cout << static_cast (device_ret.error ().type) << "\n"; } init.device = device_ret.value (); vkb::SwapchainBuilder swapchain_builder{ init.device }; auto swap_ret = swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build (); - if (!swap_ret) - { - std::cout << swap_ret.error ().msg << "\n"; + if (!swap_ret) { + std::cout << static_cast (swap_ret.error ().type) << "\n"; } init.swapchain = swap_ret.value (); return 0; } -int get_queues (Init& init, RenderData& data) -{ - data.graphics_queue = vkb::get_queue_graphics (init.device).value (); - data.present_queue = vkb::get_queue_graphics (init.device).value (); +int get_queues (Init& init, RenderData& data) { + data.graphics_queue = vkb::get_graphics_queue (init.device).value (); + data.present_queue = vkb::get_present_queue (init.device).value (); return 0; } -int create_render_pass (Init& init, RenderData& data) -{ +int create_render_pass (Init& init, RenderData& data) { VkAttachmentDescription color_attachment = {}; color_attachment.format = init.swapchain.image_format; color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; @@ -126,19 +117,16 @@ int create_render_pass (Init& init, RenderData& data) render_pass_info.dependencyCount = 1; render_pass_info.pDependencies = &dependency; - if (vkCreateRenderPass (init.device.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) - { + if (vkCreateRenderPass (init.device.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) { return -1; // failed to create render pass! } return 0; } -std::vector readFile (const std::string& filename) -{ +std::vector readFile (const std::string& filename) { std::ifstream file (filename, std::ios::ate | std::ios::binary); - if (!file.is_open ()) - { + if (!file.is_open ()) { throw std::runtime_error ("failed to open file!"); } @@ -153,31 +141,27 @@ std::vector readFile (const std::string& filename) return buffer; } -VkShaderModule createShaderModule (Init& init, const std::vector& code) -{ +VkShaderModule createShaderModule (Init& init, const std::vector& code) { VkShaderModuleCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; create_info.codeSize = code.size (); create_info.pCode = reinterpret_cast (code.data ()); VkShaderModule shaderModule; - if (vkCreateShaderModule (init.device.device, &create_info, nullptr, &shaderModule) != VK_SUCCESS) - { + if (vkCreateShaderModule (init.device.device, &create_info, nullptr, &shaderModule) != VK_SUCCESS) { return VK_NULL_HANDLE; // failed to create shader module } return shaderModule; } -int create_graphics_pipeline (Init& init, RenderData& data) -{ +int create_graphics_pipeline (Init& init, RenderData& data) { auto vert_code = readFile ("vert.spv"); auto frag_code = readFile ("frag.spv"); VkShaderModule vert_module = createShaderModule (init, vert_code); VkShaderModule frag_module = createShaderModule (init, frag_code); - if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) - { + if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) { return -1; // failed to create shader modules } @@ -260,8 +244,8 @@ int create_graphics_pipeline (Init& init, RenderData& data) pipeline_layout_info.setLayoutCount = 0; pipeline_layout_info.pushConstantRangeCount = 0; - if (vkCreatePipelineLayout (init.device.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) - { + if (vkCreatePipelineLayout ( + init.device.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) { return -1; // failed to create pipeline layout } @@ -281,8 +265,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; if (vkCreateGraphicsPipelines ( - init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphics_pipeline) != VK_SUCCESS) - { + init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphics_pipeline) != VK_SUCCESS) { return -1; // failed to create graphics pipeline } @@ -291,8 +274,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) return 0; } -int create_framebuffers (Init& init, RenderData& data) -{ +int create_framebuffers (Init& init, RenderData& data) { data.swapchain_images = vkb::get_swapchain_images (init.swapchain).value (); // init.swapchain.image_count = data.swapchain_images.size (); data.swapchain_image_views = @@ -300,8 +282,7 @@ int create_framebuffers (Init& init, RenderData& data) data.framebuffers.resize (data.swapchain_image_views.size ()); - for (size_t i = 0; i < data.swapchain_image_views.size (); i++) - { + for (size_t i = 0; i < data.swapchain_image_views.size (); i++) { VkImageView attachments[] = { data.swapchain_image_views[i] }; VkFramebufferCreateInfo framebuffer_info = {}; @@ -313,29 +294,25 @@ int create_framebuffers (Init& init, RenderData& data) framebuffer_info.height = init.swapchain.extent.height; framebuffer_info.layers = 1; - if (vkCreateFramebuffer (init.device.device, &framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS) - { + if (vkCreateFramebuffer (init.device.device, &framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS) { return -1; // failed to create framebuffer } } return 0; } -int create_command_pool (Init& init, RenderData& data) -{ +int create_command_pool (Init& init, RenderData& data) { VkCommandPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_info.queueFamilyIndex = vkb::get_queue_index_graphics (init.device); + pool_info.queueFamilyIndex = vkb::get_graphics_queue_index (init.device).value (); - if (vkCreateCommandPool (init.device.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) - { + if (vkCreateCommandPool (init.device.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) { return -1; // failed to create command pool } return 0; } -int create_command_buffers (Init& init, RenderData& data) -{ +int create_command_buffers (Init& init, RenderData& data) { data.command_buffers.resize (data.framebuffers.size ()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -344,18 +321,15 @@ int create_command_buffers (Init& init, RenderData& data) allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandBufferCount = (uint32_t)data.command_buffers.size (); - if (vkAllocateCommandBuffers (init.device.device, &allocInfo, data.command_buffers.data ()) != VK_SUCCESS) - { + if (vkAllocateCommandBuffers (init.device.device, &allocInfo, data.command_buffers.data ()) != VK_SUCCESS) { return -1; // failed to allocate command buffers; } - for (size_t i = 0; i < data.command_buffers.size (); i++) - { + for (size_t i = 0; i < data.command_buffers.size (); i++) { VkCommandBufferBeginInfo begin_info = {}; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - if (vkBeginCommandBuffer (data.command_buffers[i], &begin_info) != VK_SUCCESS) - { + if (vkBeginCommandBuffer (data.command_buffers[i], &begin_info) != VK_SUCCESS) { return -1; // failed to begin recording command buffer } @@ -378,16 +352,14 @@ int create_command_buffers (Init& init, RenderData& data) vkCmdEndRenderPass (data.command_buffers[i]); - if (vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS) - { + if (vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS) { return -1; // failed to record command buffer! } } return 0; } -int create_sync_objects (Init& init, RenderData& data) -{ +int create_sync_objects (Init& init, RenderData& data) { data.available_semaphores.resize (MAX_FRAMES_IN_FLIGHT); data.finished_semaphore.resize (MAX_FRAMES_IN_FLIGHT); data.in_flight_fences.resize (MAX_FRAMES_IN_FLIGHT); @@ -400,20 +372,17 @@ int create_sync_objects (Init& init, RenderData& data) fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - { + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { if (vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS || vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS || - vkCreateFence (init.device.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) - { + vkCreateFence (init.device.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) { return -1; // failed to create synchronization objects for a frame } } return 0; } -int draw_frame (Init& init, RenderData& data) -{ +int draw_frame (Init& init, RenderData& data) { vkWaitForFences (init.device.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX); uint32_t image_index = 0; @@ -424,8 +393,7 @@ int draw_frame (Init& init, RenderData& data) VK_NULL_HANDLE, &image_index); - if (data.image_in_flight[image_index] != VK_NULL_HANDLE) - { + if (data.image_in_flight[image_index] != VK_NULL_HANDLE) { vkWaitForFences (init.device.device, 1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX); } data.image_in_flight[image_index] = data.in_flight_fences[data.current_frame]; @@ -448,8 +416,7 @@ int draw_frame (Init& init, RenderData& data) vkResetFences (init.device.device, 1, &data.in_flight_fences[data.current_frame]); - if (vkQueueSubmit (data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) - { + if (vkQueueSubmit (data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) { return -1; //"failed to submit draw command buffer } @@ -471,10 +438,8 @@ int draw_frame (Init& init, RenderData& data) return 0; } -void cleanup (Init& init, RenderData& data) -{ - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - { +void cleanup (Init& init, RenderData& data) { + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { vkDestroySemaphore (init.device.device, data.finished_semaphore[i], nullptr); vkDestroySemaphore (init.device.device, data.available_semaphores[i], nullptr); vkDestroyFence (init.device.device, data.in_flight_fences[i], nullptr); @@ -482,8 +447,7 @@ void cleanup (Init& init, RenderData& data) vkDestroyCommandPool (init.device.device, data.command_pool, nullptr); - for (auto framebuffer : data.framebuffers) - { + for (auto framebuffer : data.framebuffers) { vkDestroyFramebuffer (init.device.device, framebuffer, nullptr); } @@ -491,8 +455,7 @@ void cleanup (Init& init, RenderData& data) vkDestroyPipelineLayout (init.device.device, data.pipeline_layout, nullptr); vkDestroyRenderPass (init.device.device, data.render_pass, nullptr); - for (auto imageView : data.swapchain_image_views) - { + for (auto imageView : data.swapchain_image_views) { vkDestroyImageView (init.device.device, imageView, nullptr); } @@ -503,8 +466,7 @@ void cleanup (Init& init, RenderData& data) destroy_window_glfw (init.window); } -int main () -{ +int main () { Init init; RenderData render_data; @@ -518,18 +480,15 @@ int main () res = create_command_buffers (init, render_data); res = create_sync_objects (init, render_data); - if (res != 0) - { + if (res != 0) { std::cout << "failed to initialize vulkan\n"; return -1; } - while (!glfwWindowShouldClose (init.window)) - { + while (!glfwWindowShouldClose (init.window)) { glfwPollEvents (); int res = draw_frame (init, render_data); - if (res != 0) - { + if (res != 0) { std::cout << "failed to draw frame \n"; return -1; } diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index b511a44..4d0ba74 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -15,13 +15,13 @@ auto get_vector (F&& f, Ts&&... ts) -> Expected, VkResult> { do { err = f (ts..., &count, nullptr); if (err) { - return Error{ err, "" }; + return err; }; results.resize (count); err = f (ts..., &count, results.data ()); } while (err == VK_INCOMPLETE); - if (err) { - return Error{ err, "" }; + if (err != VK_SUCCESS) { + return err; }; return results; } @@ -146,7 +146,7 @@ void destroy_instance (Instance instance) { } } -detail::Expected InstanceBuilder::build () { +detail::Expected> InstanceBuilder::build () { VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -189,7 +189,7 @@ detail::Expected InstanceBuilder::build () { } bool all_layers_supported = detail::check_layers_supported (layers); if (!all_layers_supported) { - return detail::Error{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" }; + return detail::Error{ InstanceError::requested_layers_not_present }; } VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {}; @@ -234,7 +234,8 @@ detail::Expected InstanceBuilder::build () { Instance instance; VkResult res = vkCreateInstance (&instance_create_info, nullptr, &instance.instance); - if (res != VK_SUCCESS) return detail::Error{ res, "Failed to create instance" }; + if (res != VK_SUCCESS) + return detail::Error{ InstanceError::failed_create_instance, res }; if (info.use_debug_messenger) { res = create_debug_utils_messenger (instance.instance, @@ -243,7 +244,7 @@ detail::Expected InstanceBuilder::build () { info.debug_message_type, &instance.debug_messenger); if (res != VK_SUCCESS) { - return detail::Error{ res, "Failed to create setup debug callback" }; + return detail::Error{ InstanceError::failed_create_debug_messenger, res }; } } @@ -336,30 +337,33 @@ struct SurfaceSupportDetails { std::vector present_modes; }; -Expected query_surface_support_details ( +enum class SurfaceSupportError { + surface_handle_null, + failed_get_surface_capabilities, + failed_enumerate_surface_formats, + failed_enumerate_present_modes +}; + +Expected> query_surface_support_details ( VkPhysicalDevice phys_device, VkSurfaceKHR surface) { if (surface == VK_NULL_HANDLE) - return Error{ VK_ERROR_INITIALIZATION_FAILED, "surface handle was null" }; + return detail::Error{ SurfaceSupportError::surface_handle_null }; VkSurfaceCapabilitiesKHR capabilities; VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities); if (res != VK_SUCCESS) { - // error - /* possible errors - VK_ERROR_OUT_OF_HOST_MEMORY - VK_ERROR_OUT_OF_DEVICE_MEMORY - VK_ERROR_SURFACE_LOST_KHR - */ + return detail::Error{ SurfaceSupportError::failed_get_surface_capabilities, res }; } auto formats = detail::get_vector ( vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface); if (!formats.has_value ()) - return detail::Error{ formats.error ().error_code, "Couldn't get surface formats" }; + return detail::Error{ SurfaceSupportError::failed_enumerate_surface_formats, + formats.error () }; auto present_modes = detail::get_vector ( vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface); if (!present_modes.has_value ()) - return detail::Error{ formats.error ().error_code, "Couldn't get surface present modes" }; - + return detail::Error{ SurfaceSupportError::failed_enumerate_present_modes, + formats.error () }; return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () }; } @@ -580,13 +584,14 @@ PhysicalDeviceSelector::PhysicalDeviceSelector (Instance const& instance) { criteria.require_present = !instance.headless; } -detail::Expected PhysicalDeviceSelector::select () { +detail::Expected> PhysicalDeviceSelector::select () { auto physical_devices = detail::get_vector (vkEnumeratePhysicalDevices, info.instance); if (!physical_devices.has_value ()) { - return detail::Error{ physical_devices.error ().error_code, "Failed to find physical devices" }; + return detail::Error{ PhysicalDeviceError::failed_enumerate_physical_devices, + physical_devices.error () }; } if (physical_devices.value ().size () == 0) { - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "No physical devices found" }; + return detail::Error{ PhysicalDeviceError::no_physical_devices_found }; } PhysicalDevice physical_device; @@ -605,7 +610,7 @@ detail::Expected PhysicalDeviceSelector::select () { } if (physical_device.phys_device == VK_NULL_HANDLE) { - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to find a suitable GPU!" }; + return detail::Error{ PhysicalDeviceError::no_suitable_device }; } physical_device.surface = info.surface; @@ -703,7 +708,7 @@ DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device) { info.extensions = phys_device.extensions_to_enable; } -detail::Expected DeviceBuilder::build () { +detail::Expected> DeviceBuilder::build () { auto queue_families = detail::get_vector_noerror ( vkGetPhysicalDeviceQueueFamilyProperties, info.physical_device.phys_device); @@ -739,7 +744,7 @@ detail::Expected DeviceBuilder::build () { VkResult res = vkCreateDevice (info.physical_device.phys_device, &device_create_info, nullptr, &device.device); if (res != VK_SUCCESS) { - return detail::Error{ res, "Couldn't create device" }; + return detail::Error{ DeviceError::failed_create_device, res }; } device.physical_device = info.physical_device; device.surface = info.physical_device.surface; @@ -753,38 +758,62 @@ template DeviceBuilder& DeviceBuilder::add_pNext (T* structure) { // ---- Getting Queues ---- // +detail::Expected> get_present_queue_index (Device const& device) { + int present = get_present_queue_index ( + device.physical_device.phys_device, device.surface, device.queue_families); + if (present < 0) return detail::Error{ QueueError::present_unavailable }; + return static_cast (present); +} +detail::Expected> get_graphics_queue_index (Device const& device) { + int graphics = get_graphics_queue_index (device.queue_families); + if (graphics < 0) return detail::Error{ QueueError::invalid_queue_family_index }; + return static_cast (graphics); +} +detail::Expected> get_compute_queue_index (Device const& device) { + int compute = get_distinct_compute_queue_index (device.queue_families); + if (compute < 0) return detail::Error{ QueueError::compute_unavailable }; + return static_cast (compute); +} +detail::Expected> get_transfer_queue_index (Device const& device) { + int transfer = get_distinct_transfer_queue_index (device.queue_families); + if (transfer < 0) return detail::Error{ QueueError::transfer_unavailable }; + return static_cast (transfer); +} + + VkQueue get_queue (VkDevice device, int32_t family) { VkQueue out_queue; vkGetDeviceQueue (device, family, 0, &out_queue); return out_queue; } -detail::Expected get_present_queue (Device const& device) { - int present = get_present_queue_index (device.physical_device, device.surface, device.queue_families); +detail::Expected> get_present_queue (Device const& device) { + int present = get_present_queue_index ( + device.physical_device.phys_device, device.surface, device.queue_families); if (present >= 0) { return get_queue (device.device, present); } - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "presentation queue is not available" }; + return detail::Error{ QueueError::present_unavailable }; } -detail::Expected get_graphics_queue (Device const& device) { - int graphics = get_graphics_queue_index (device.physical_device, device.surface, device.queue_families); +detail::Expected> get_graphics_queue (Device const& device) { + int graphics = get_graphics_queue_index (device.queue_families); if (graphics >= 0) { return get_queue (device.device, graphics); } - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested queue family is not available" }; + return detail::Error{ QueueError::invalid_queue_family_index }; } -detail::Expected get_compute_queue (Device const& device) { - int compute = get_distinct_compute_queue_index (device.physical_device, device.surface, device.queue_families); +detail::Expected> get_compute_queue (Device const& device) { + int compute = get_distinct_compute_queue_index (device.queue_families); if (compute >= 0) { return get_queue (device.device, compute); } - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested queue family is not available" }; + return detail::Error{ QueueError::compute_unavailable }; } -detail::Expected get_transfer_queue (Device const& device) { - int transfer = get_distinct_transfer_queue_index (device.physical_device, device.surface, device.queue_families); +detail::Expected> get_transfer_queue (Device const& device) { + int transfer = get_distinct_transfer_queue_index (device.queue_families); if (transfer >= 0) { return get_queue (device.device, transfer); } - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested queue family is not available" }; + return detail::Error{ QueueError::transfer_unavailable }; } @@ -840,21 +869,34 @@ SwapchainBuilder::SwapchainBuilder (Device const& device) { info.device = device.device; info.physical_device = device.physical_device.phys_device; info.surface = device.surface; + int present = get_present_queue_index ( + device.physical_device.phys_device, device.surface, device.queue_families); + int graphics = get_graphics_queue_index (device.queue_families); + + info.graphics_queue_index = graphics; + info.present_queue_index = present; } -SwapchainBuilder::SwapchainBuilder ( - VkPhysicalDevice const physical_device, VkDevice const device, VkSurfaceKHR const surface) { +SwapchainBuilder::SwapchainBuilder (VkPhysicalDevice const physical_device, + VkDevice const device, + VkSurfaceKHR const surface, + uint32_t graphics_queue_index, + uint32_t present_queue_index) { info.physical_device = physical_device; info.device = device; info.surface = surface; + info.graphics_queue_index = graphics_queue_index; + info.present_queue_index = present_queue_index; } -detail::Expected SwapchainBuilder::build () { +detail::Expected> SwapchainBuilder::build () { if (info.desired_formats.size () == 0) use_default_format_selection (); if (info.desired_present_modes.size () == 0) use_default_present_mode_selection (); auto surface_support = detail::query_surface_support_details (info.physical_device, info.surface); - if (!surface_support.has_value ()) return surface_support.error (); + if (!surface_support.has_value ()) + return detail::Error{ SwapchainError::failed_query_surface_support_details, + surface_support.error ().vk_result }; VkSurfaceFormatKHR surface_format = detail::find_surface_format (surface_support.value ().formats, info.desired_formats); VkPresentModeKHR present_mode = @@ -879,11 +921,9 @@ detail::Expected SwapchainBuilder::build () { swapchain_create_info.imageArrayLayers = 1; swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - QueueFamilies indices = find_queue_families (info.physical_device, info.surface); - uint32_t queue_family_indices[] = { static_cast (indices.graphics), - static_cast (indices.present) }; + uint32_t queue_family_indices[] = { info.graphics_queue_index, info.present_queue_index }; - if (indices.graphics != indices.present) { + if (info.graphics_queue_index != info.present_queue_index) { swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchain_create_info.queueFamilyIndexCount = 2; swapchain_create_info.pQueueFamilyIndices = queue_family_indices; @@ -899,7 +939,7 @@ detail::Expected SwapchainBuilder::build () { Swapchain swapchain{}; VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain); if (res != VK_SUCCESS) { - return detail::Error{ res, "Failed to create swapchain" }; + return detail::Error{ SwapchainError::failed_create_swapchain, res }; } swapchain.device = info.device; swapchain.image_format = surface_format.format; @@ -908,22 +948,24 @@ detail::Expected SwapchainBuilder::build () { auto images = get_swapchain_images (swapchain); swapchain.image_count = images.value ().size (); return swapchain; -} -detail::Expected SwapchainBuilder::recreate (Swapchain const& swapchain) { +} // namespace vkb +detail::Expected> SwapchainBuilder::recreate (Swapchain const& swapchain) { info.old_swapchain = swapchain.swapchain; return build (); } -detail::Expected, VkResult> get_swapchain_images (Swapchain const& swapchain) { +detail::Expected, detail::Error> get_swapchain_images ( + Swapchain const& swapchain) { auto swapchain_images = detail::get_vector (vkGetSwapchainImagesKHR, swapchain.device, swapchain.swapchain); if (!swapchain_images) { - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to get swapchain Images" }; + return detail::Error{ SwapchainError::failed_get_swapchain_images, + swapchain_images.error () }; } return swapchain_images.value (); } -detail::Expected, VkResult> get_swapchain_image_views ( - Swapchain const& swapchain, std::vector const& images) { +detail::Expected, detail::Error> +get_swapchain_image_views (Swapchain const& swapchain, std::vector const& images) { std::vector views{ swapchain.image_count }; for (size_t i = 0; i < swapchain.image_count; i++) { @@ -944,7 +986,7 @@ detail::Expected, VkResult> get_swapchain_image_views ( VkResult res = vkCreateImageView (swapchain.device, &createInfo, nullptr, &views[i]); if (res != VK_SUCCESS) - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to create image views" }; + return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res }; } return views; } diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 3786141..9cac10b 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -11,33 +11,32 @@ namespace vkb { namespace detail { +template struct Error { + explicit Error (ErrorType type, VkResult result = VK_SUCCESS) + : type (type), vk_result (result) {} -enum class BootstrapErrorType : uint32_t { - + ErrorType type; + VkResult vk_result; // optional error value if a vulkan call failed }; -struct Error { - VkResult error_code; - const char* msg; -}; template class Expected { public: Expected (const E& expect) : m_expect{ expect }, m_init{ true } {} Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {} - Expected (const Error& error) : m_error{ error }, m_init{ false } {} - Expected (Error&& error) : m_error{ std::move (error) }, m_init{ false } {} + Expected (const U& error) : m_error{ error }, m_init{ false } {} + Expected (U&& error) : m_error{ std::move (error) }, m_init{ false } {} ~Expected () { destroy (); } Expected (Expected const& expected) : m_init (expected.m_init) { if (m_init) new (&m_expect) E{ expected.m_expect }; else - new (&m_error) Error{ expected.m_error }; + new (&m_error) U{ expected.m_error }; } Expected (Expected&& expected) : m_init (expected.m_init) { if (m_init) new (&m_expect) E{ std::move (expected.m_expect) }; else - new (&m_error) Error{ std::move (expected.m_error) }; + new (&m_error) U{ std::move (expected.m_error) }; expected.destroy (); } @@ -53,16 +52,16 @@ template class Expected { new (&m_expect) E{ std::move (expect) }; return *this; } - Expected& operator= (const Error& error) { + Expected& operator= (const U& error) { destroy (); m_init = false; - new (&m_error) Error{ error }; + new (&m_error) U{ error }; return *this; } - Expected& operator= (Error&& error) { + Expected& operator= (U&& error) { destroy (); m_init = false; - new (&m_error) Error{ std::move (error) }; + new (&m_error) U{ std::move (error) }; return *this; } // clang-format off @@ -75,10 +74,10 @@ template class Expected { E& value () & { assert (m_init); return m_expect; } const E&& value () const&& { assert (m_init); return std::move (m_expect); } E&& value () && { assert (m_init); return std::move (m_expect); } - const Error& error () const& { assert (!m_init); return m_error; } - Error& error () & { assert (!m_init); return m_error; } - const Error&& error () const&& { assert (!m_init); return std::move (m_error); } - Error&& error () && { assert (!m_init); return std::move (m_error); } + const U& error () const& { assert (!m_init); return m_error; } + U& error () & { assert (!m_init); return m_error; } + const U&& error () const&& { assert (!m_init); return std::move (m_error); } + U&& error () && { assert (!m_init); return std::move (m_error); } // clang-format on bool has_value () const { return m_init; } explicit operator bool () const { return m_init; } @@ -88,19 +87,25 @@ template class Expected { if (m_init) m_expect.~E (); else - m_error.~Error (); + m_error.~U (); } union { E m_expect; - Error m_error; + U m_error; }; bool m_init; }; /* TODO implement operator == and operator != as friend or global */ - } // namespace detail +enum class InstanceError { + failed_create_instance, + failed_create_debug_messenger, + requested_layers_not_present, + requested_extensions_not_present +}; + class InstanceBuilder; class PhysicalDeviceSelector; @@ -121,7 +126,7 @@ void destroy_instance (Instance instance); // release instance resources class InstanceBuilder { public: - detail::Expected build (); // use builder pattern + detail::Expected> build (); // use builder pattern InstanceBuilder& set_app_name (std::string app_name); InstanceBuilder& set_engine_name (std::string engine_name); @@ -200,6 +205,13 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessag void* pUserData); // ---- Physical Device ---- // +enum class PhysicalDeviceError { + failed_enumerate_physical_devices, + no_physical_devices_found, + no_suitable_device, + +}; + class PhysicalDeviceSelector; class DeviceBuilder; @@ -218,7 +230,7 @@ struct PhysicalDeviceSelector { public: PhysicalDeviceSelector (Instance const& instance); - detail::Expected select (); + detail::Expected> select (); PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance); @@ -283,6 +295,9 @@ struct PhysicalDeviceSelector { enum class QueueType : uint8_t { primary, compute, transfer }; // ---- Device ---- // +enum class DeviceError { + failed_create_device, +}; struct Device { VkDevice device = VK_NULL_HANDLE; @@ -296,13 +311,13 @@ void destroy_device (Device device); class DeviceBuilder { public: DeviceBuilder (PhysicalDevice device); - detail::Expected build (); + detail::Expected> build (); template DeviceBuilder& add_pNext (T* structure); private: struct DeviceInfo { - VkDeviceCreateFlags flags; + VkDeviceCreateFlags flags = 0; std::vector pNext_chain; PhysicalDevice physical_device; std::vector extensions; @@ -311,14 +326,34 @@ class DeviceBuilder { // ---- Getting Queues ---- // -detail::Expected get_present_queue (Device const& device); -detail::Expected get_graphics_queue (Device const& device); -detail::Expected get_compute_queue (Device const& device); -detail::Expected get_transfer_queue (Device const& device); +enum class QueueError { + present_unavailable, + compute_unavailable, + transfer_unavailable, + queue_index_out_of_range, + invalid_queue_family_index +}; + +detail::Expected> get_present_queue_index (Device const& device); +detail::Expected> get_graphics_queue_index (Device const& device); +detail::Expected> get_compute_queue_index (Device const& device); +detail::Expected> get_transfer_queue_index (Device const& device); + +detail::Expected> get_present_queue (Device const& device); +detail::Expected> get_graphics_queue (Device const& device); +detail::Expected> get_compute_queue (Device const& device); +detail::Expected> get_transfer_queue (Device const& device); // ---- Swapchain ---- // +enum class SwapchainError { + failed_query_surface_support_details, + failed_create_swapchain, + failed_get_swapchain_images, + failed_create_swapchain_image_views, +}; + struct Swapchain { VkDevice device = VK_NULL_HANDLE; VkSwapchainKHR swapchain = VK_NULL_HANDLE; @@ -329,17 +364,22 @@ struct Swapchain { void destroy_swapchain (Swapchain const& swapchain); -detail::Expected, VkResult> get_swapchain_images (Swapchain const& swapchain); -detail::Expected, VkResult> get_swapchain_image_views ( - Swapchain const& swapchain, std::vector const& images); +detail::Expected, detail::Error> get_swapchain_images ( + Swapchain const& swapchain); +detail::Expected, detail::Error> +get_swapchain_image_views (Swapchain const& swapchain, std::vector const& images); class SwapchainBuilder { public: SwapchainBuilder (Device const& device); - SwapchainBuilder (VkPhysicalDevice const physical_device, VkDevice const device, VkSurfaceKHR const surface); + SwapchainBuilder (VkPhysicalDevice const physical_device, + VkDevice const device, + VkSurfaceKHR const surface, + uint32_t graphics_queue_index, + uint32_t present_queue_index); - detail::Expected build (); - detail::Expected recreate (Swapchain const& swapchain); + detail::Expected> build (); + detail::Expected> recreate (Swapchain const& swapchain); // SwapchainBuilder& set_desired_image_count (uint32_t count); // SwapchainBuilder& set_maximum_image_count (uint32_t count); diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index 529fe2a..945c84b 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -1,14 +1,12 @@ #include "common.h" -int test_happy_path () -{ +int test_happy_path () { auto window = create_window_glfw (); vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.set_default_debug_messenger ().build (); - if (!instance_ret) - { - std::cout << instance_ret.error ().msg << "\n"; + if (!instance_ret) { + std::cout << static_cast (instance_ret.error ().type) << "\n"; return -1; // couldn't make instance } vkb::Instance instance = instance_ret.value (); @@ -37,8 +35,7 @@ int test_happy_path () } -int test_instance_basic () -{ +int test_instance_basic () { vkb::InstanceBuilder builder; @@ -56,15 +53,13 @@ int test_instance_basic () }) .set_api_version (1, 2, 111) .build (); - if (!instance_ret.has_value ()) - { + if (!instance_ret.has_value ()) { return 1; } return 0; } -int test_instance_headless () -{ +int test_instance_headless () { vkb::InstanceBuilder builder; @@ -76,15 +71,13 @@ int test_instance_headless () .set_api_version (1, 0, 34) .set_default_debug_messenger () .build (); - if (!instance_ret.has_value ()) - { + if (!instance_ret.has_value ()) { return 1; } return 0; } -int test_physical_device_selection () -{ +int test_physical_device_selection () { vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.set_default_debug_messenger ().build (); auto instance = instance_ret.value (); @@ -98,8 +91,7 @@ int test_physical_device_selection () .set_minimum_version (1, 0) .set_desired_version (1, 1) .select (); - if (!phys_dev_ret.has_value ()) - { + if (!phys_dev_ret.has_value ()) { return -1; } vkb::destroy_instance (instance); @@ -107,8 +99,7 @@ int test_physical_device_selection () return 0; } -int test_device_creation () -{ +int test_device_creation () { vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.set_default_debug_messenger ().build (); auto instance = instance_ret.value (); @@ -121,9 +112,8 @@ int test_device_creation () vkb::DeviceBuilder device_builder (phys_dev); auto dev_ret = device_builder.build (); - if (!dev_ret.has_value ()) - { - printf ("%s\n", dev_ret.error ().msg); + if (!dev_ret.has_value ()) { + printf ("couldn't create device %i\n", static_cast (dev_ret.error ().type)); return -1; } @@ -133,8 +123,7 @@ int test_device_creation () return 0; } -int main () -{ +int main () { printf ("happy path\n"); test_happy_path ();