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.
This commit is contained in:
Charles Giessen 2020-02-10 11:29:09 -07:00
parent 5375504bb3
commit 3e7e283e3f
4 changed files with 232 additions and 202 deletions

View File

@ -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<uint32_t> (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<uint32_t> (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<uint32_t> (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<uint32_t> (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<char> readFile (const std::string& filename)
{
std::vector<char> 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<char> readFile (const std::string& filename)
return buffer;
}
VkShaderModule createShaderModule (Init& init, const std::vector<char>& code)
{
VkShaderModule createShaderModule (Init& init, const std::vector<char>& code) {
VkShaderModuleCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
create_info.codeSize = code.size ();
create_info.pCode = reinterpret_cast<const uint32_t*> (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;
}

View File

@ -15,13 +15,13 @@ auto get_vector (F&& f, Ts&&... ts) -> Expected<std::vector<T>, 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<Instance, VkResult> InstanceBuilder::build () {
detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build () {
VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
@ -189,7 +189,7 @@ detail::Expected<Instance, VkResult> 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>{ InstanceError::requested_layers_not_present };
}
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
@ -234,7 +234,8 @@ detail::Expected<Instance, VkResult> 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>{ InstanceError::failed_create_instance, res };
if (info.use_debug_messenger) {
res = create_debug_utils_messenger (instance.instance,
@ -243,7 +244,7 @@ detail::Expected<Instance, VkResult> 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>{ InstanceError::failed_create_debug_messenger, res };
}
}
@ -336,30 +337,33 @@ struct SurfaceSupportDetails {
std::vector<VkPresentModeKHR> present_modes;
};
Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
enum class SurfaceSupportError {
surface_handle_null,
failed_get_surface_capabilities,
failed_enumerate_surface_formats,
failed_enumerate_present_modes
};
Expected<SurfaceSupportDetails, detail::Error<SurfaceSupportError>> 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>{ 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>{ SurfaceSupportError::failed_get_surface_capabilities, res };
}
auto formats = detail::get_vector<VkSurfaceFormatKHR> (
vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
if (!formats.has_value ())
return detail::Error{ formats.error ().error_code, "Couldn't get surface formats" };
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_enumerate_surface_formats,
formats.error () };
auto present_modes = detail::get_vector<VkPresentModeKHR> (
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>{ 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<PhysicalDevice, VkResult> PhysicalDeviceSelector::select () {
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> PhysicalDeviceSelector::select () {
auto physical_devices = detail::get_vector<VkPhysicalDevice> (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>{ 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>{ PhysicalDeviceError::no_physical_devices_found };
}
PhysicalDevice physical_device;
@ -605,7 +610,7 @@ detail::Expected<PhysicalDevice, VkResult> 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>{ 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<Device, VkResult> DeviceBuilder::build () {
detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties> (
vkGetPhysicalDeviceQueueFamilyProperties, info.physical_device.phys_device);
@ -739,7 +744,7 @@ detail::Expected<Device, VkResult> 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>{ DeviceError::failed_create_device, res };
}
device.physical_device = info.physical_device;
device.surface = info.physical_device.surface;
@ -753,38 +758,62 @@ template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure) {
// ---- Getting Queues ---- //
detail::Expected<uint32_t, detail::Error<QueueError>> 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>{ QueueError::present_unavailable };
return static_cast<uint32_t> (present);
}
detail::Expected<uint32_t, detail::Error<QueueError>> get_graphics_queue_index (Device const& device) {
int graphics = get_graphics_queue_index (device.queue_families);
if (graphics < 0) return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
return static_cast<uint32_t> (graphics);
}
detail::Expected<uint32_t, detail::Error<QueueError>> get_compute_queue_index (Device const& device) {
int compute = get_distinct_compute_queue_index (device.queue_families);
if (compute < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable };
return static_cast<uint32_t> (compute);
}
detail::Expected<uint32_t, detail::Error<QueueError>> get_transfer_queue_index (Device const& device) {
int transfer = get_distinct_transfer_queue_index (device.queue_families);
if (transfer < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable };
return static_cast<uint32_t> (transfer);
}
VkQueue get_queue (VkDevice device, int32_t family) {
VkQueue out_queue;
vkGetDeviceQueue (device, family, 0, &out_queue);
return out_queue;
}
detail::Expected<VkQueue, VkResult> get_present_queue (Device const& device) {
int present = get_present_queue_index (device.physical_device, device.surface, device.queue_families);
detail::Expected<VkQueue, detail::Error<QueueError>> 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>{ QueueError::present_unavailable };
}
detail::Expected<VkQueue, VkResult> get_graphics_queue (Device const& device) {
int graphics = get_graphics_queue_index (device.physical_device, device.surface, device.queue_families);
detail::Expected<VkQueue, detail::Error<QueueError>> 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>{ QueueError::invalid_queue_family_index };
}
detail::Expected<VkQueue, VkResult> get_compute_queue (Device const& device) {
int compute = get_distinct_compute_queue_index (device.physical_device, device.surface, device.queue_families);
detail::Expected<VkQueue, detail::Error<QueueError>> 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>{ QueueError::compute_unavailable };
}
detail::Expected<VkQueue, VkResult> get_transfer_queue (Device const& device) {
int transfer = get_distinct_transfer_queue_index (device.physical_device, device.surface, device.queue_families);
detail::Expected<VkQueue, detail::Error<QueueError>> 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>{ 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<Swapchain, VkResult> SwapchainBuilder::build () {
detail::Expected<Swapchain, detail::Error<SwapchainError>> 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>{ 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<Swapchain, VkResult> 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<uint32_t> (indices.graphics),
static_cast<uint32_t> (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<Swapchain, VkResult> 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>{ SwapchainError::failed_create_swapchain, res };
}
swapchain.device = info.device;
swapchain.image_format = surface_format.format;
@ -908,22 +948,24 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::build () {
auto images = get_swapchain_images (swapchain);
swapchain.image_count = images.value ().size ();
return swapchain;
}
detail::Expected<Swapchain, VkResult> SwapchainBuilder::recreate (Swapchain const& swapchain) {
} // namespace vkb
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::recreate (Swapchain const& swapchain) {
info.old_swapchain = swapchain.swapchain;
return build ();
}
detail::Expected<std::vector<VkImage>, VkResult> get_swapchain_images (Swapchain const& swapchain) {
detail::Expected<std::vector<VkImage>, detail::Error<SwapchainError>> get_swapchain_images (
Swapchain const& swapchain) {
auto swapchain_images =
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, swapchain.device, swapchain.swapchain);
if (!swapchain_images) {
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to get swapchain Images" };
return detail::Error<SwapchainError>{ SwapchainError::failed_get_swapchain_images,
swapchain_images.error () };
}
return swapchain_images.value ();
}
detail::Expected<std::vector<VkImageView>, VkResult> get_swapchain_image_views (
Swapchain const& swapchain, std::vector<VkImage> const& images) {
detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>>
get_swapchain_image_views (Swapchain const& swapchain, std::vector<VkImage> const& images) {
std::vector<VkImageView> views{ swapchain.image_count };
for (size_t i = 0; i < swapchain.image_count; i++) {
@ -944,7 +986,7 @@ detail::Expected<std::vector<VkImageView>, 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>{ SwapchainError::failed_create_swapchain_image_views, res };
}
return views;
}

View File

@ -11,33 +11,32 @@
namespace vkb {
namespace detail {
template <typename ErrorType> 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 <typename E, typename U> 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 <typename E, typename U> 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 <typename E, typename U> 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 <typename E, typename U> 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<Instance, VkResult> build (); // use builder pattern
detail::Expected<Instance, detail::Error<InstanceError>> 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<PhysicalDevice, VkResult> select ();
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> 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<Device, VkResult> build ();
detail::Expected<Device, detail::Error<DeviceError>> build ();
template <typename T> DeviceBuilder& add_pNext (T* structure);
private:
struct DeviceInfo {
VkDeviceCreateFlags flags;
VkDeviceCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
PhysicalDevice physical_device;
std::vector<std::string> extensions;
@ -311,14 +326,34 @@ class DeviceBuilder {
// ---- Getting Queues ---- //
detail::Expected<VkQueue, VkResult> get_present_queue (Device const& device);
detail::Expected<VkQueue, VkResult> get_graphics_queue (Device const& device);
detail::Expected<VkQueue, VkResult> get_compute_queue (Device const& device);
detail::Expected<VkQueue, VkResult> 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<uint32_t, detail::Error<QueueError>> get_present_queue_index (Device const& device);
detail::Expected<uint32_t, detail::Error<QueueError>> get_graphics_queue_index (Device const& device);
detail::Expected<uint32_t, detail::Error<QueueError>> get_compute_queue_index (Device const& device);
detail::Expected<uint32_t, detail::Error<QueueError>> get_transfer_queue_index (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> get_present_queue (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> get_graphics_queue (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> get_compute_queue (Device const& device);
detail::Expected<VkQueue, detail::Error<QueueError>> 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<std::vector<VkImage>, VkResult> get_swapchain_images (Swapchain const& swapchain);
detail::Expected<std::vector<VkImageView>, VkResult> get_swapchain_image_views (
Swapchain const& swapchain, std::vector<VkImage> const& images);
detail::Expected<std::vector<VkImage>, detail::Error<SwapchainError>> get_swapchain_images (
Swapchain const& swapchain);
detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>>
get_swapchain_image_views (Swapchain const& swapchain, std::vector<VkImage> 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<Swapchain, VkResult> build ();
detail::Expected<Swapchain, VkResult> recreate (Swapchain const& swapchain);
detail::Expected<Swapchain, detail::Error<SwapchainError>> build ();
detail::Expected<Swapchain, detail::Error<SwapchainError>> recreate (Swapchain const& swapchain);
// SwapchainBuilder& set_desired_image_count (uint32_t count);
// SwapchainBuilder& set_maximum_image_count (uint32_t count);

View File

@ -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<uint32_t> (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<uint32_t> (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 ();