diff options
-rw-r--r-- | src/common.c | 1 | ||||
-rw-r--r-- | src/common.h | 4 | ||||
-rw-r--r-- | src/device.c | 385 | ||||
-rw-r--r-- | src/device.h | 22 | ||||
-rw-r--r-- | src/main.c | 18 |
5 files changed, 314 insertions, 116 deletions
diff --git a/src/common.c b/src/common.c index 084c584..d3773c4 100644 --- a/src/common.c +++ b/src/common.c @@ -1,5 +1,6 @@ #include <string.h> #include <errno.h> + #include "common.h" void *xmalloc(size_t size) diff --git a/src/common.h b/src/common.h index e10649a..1c80ab8 100644 --- a/src/common.h +++ b/src/common.h @@ -3,7 +3,6 @@ #include <stdio.h> #include <stdlib.h> -#include <stdint.h> #define ARR_SIZE(a) (sizeof(a)/sizeof(*(a))) @@ -24,9 +23,6 @@ abort(); \ } while(0) -#define MAKE_VERSION(major, minor, patch) \ - ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) - void *xmalloc(size_t size); void *xcalloc(size_t nmemb, size_t size); void *xrealloc(void *ptr, size_t size); diff --git a/src/device.c b/src/device.c index 9836db1..75a727d 100644 --- a/src/device.c +++ b/src/device.c @@ -8,48 +8,71 @@ // TODO: add error checking // TODO: add log output +#define CLAMP(val, min, max) (((val) < (min)) ? (min) : ((val) > (max) ? (max) : (val))) + #ifdef DEBUG char *validation_layers[] = { "VK_LAYER_KHRONOS_validation" }; #endif -enum { - QUEUE_FAMILY_COUNT = 2, - - QUEUE_FAMILY_GRAPHICS_FAMILY = 1 << 0, - QUEUE_FAMILY_PRESENT_FAMILY = 1 << 1, - - QUEUE_FAMILY_ALL = QUEUE_FAMILY_GRAPHICS_FAMILY | - QUEUE_FAMILY_PRESENT_FAMILY, +char *device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME }; struct queue_family_idx { - uint32_t graphics_family; - uint32_t present_family; + u32 graphics_family; + bool has_graphics_family; + + u32 present_family; + bool has_present_family; +}; + +struct swap_chain_support_details { + VkSurfaceCapabilitiesKHR capabilities; + + VkSurfaceFormatKHR *formats; + u32 nformats; + + VkPresentModeKHR *present_modes; + u32 npresent_modes; }; // most function that return an int follow this scheme: // 0 - success; 1 - error; (sometimes -1 - fatal error) -// if the function has 'has' or 'is', then -// 0 - fail; 1 - success (sometimes -1 - fatal error) - +// -- Major Functions --- static int create_instance(device_t device, struct device_info *info); static int create_surface(device_t device, struct device_info *info); static int create_physical_device(device_t device, struct device_info *info); static int create_logical_device(device_t device, struct device_info *info); +static int create_swap_chain(device_t device, struct device_info *info); -static int is_device_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface); +// --- Helper Function --- +static bool device_is_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface); +static bool device_has_extension_support(VkPhysicalDevice phy_device); +static int device_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family); -// does not follow the general scheme, see implementation for details -static int find_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family); +static int swap_chain_support(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct swap_chain_support_details *details); +static void swap_chain_free_support_details(struct swap_chain_support_details *details); +static int swap_chain_choose_format(VkSurfaceFormatKHR* formats, u32 nformats, VkSurfaceFormatKHR *format); +static int swap_chain_choose_present_mode(VkPresentModeKHR *modes, u32 nmodes, VkPresentModeKHR *mode); +static int swap_chain_get_extent(VkSurfaceCapabilitiesKHR capabilities, VkExtent2D *extent); +// --- Debug Functions --- #ifdef DEBUG +static bool instance_has_validation_layers(const char * const *layers, u32 nlayers); + static int create_debug_messenger(device_t device, struct device_info* info); -static int has_validation_layer_support(const char * const *layers, uint32_t nlayers); -static void populate_debug_messenger_info(VkDebugUtilsMessengerCreateInfoEXT *info); +static void debug_messenger_populate_info(VkDebugUtilsMessengerCreateInfoEXT *info); + +static VKAPI_ATTR VkBool32 VKAPI_CALL debug_messenger_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData); +// Vulkan Wrappers VkResult CreateDebugUtilsMessengerEXT( VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, @@ -59,11 +82,6 @@ void DestroyDebugUtilsMessengerEXT( VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator); -static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData); #endif #define CHECK(func) if(func(device, info)) { goto fail; } @@ -71,6 +89,9 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( device_t device_create(struct device_info *info) { device_t device = xmalloc(sizeof(struct device)); + device->instance = VK_NULL_HANDLE; + device->logical_device = VK_NULL_HANDLE; + device->swap_chain = VK_NULL_HANDLE; CHECK(create_instance); CHECK(create_surface); @@ -79,6 +100,7 @@ device_t device_create(struct device_info *info) #endif CHECK(create_physical_device); CHECK(create_logical_device); + CHECK(create_swap_chain) return device; fail: @@ -90,14 +112,16 @@ void device_destroy(device_t device) { if(!device) return; + free(device->swap_chain_images); + vkDestroySwapchainKHR(device->logical_device, device->swap_chain, NULL); + vkDestroyDevice(device->logical_device, NULL); #ifdef DEBUG DestroyDebugUtilsMessengerEXT(device->instance, device->debug_messenger, NULL); #endif - + vkDestroySurfaceKHR(device->instance, device->surface, NULL); - vkDestroyInstance(device->instance, NULL); free(device); @@ -105,6 +129,8 @@ void device_destroy(device_t device) static int create_instance(device_t device, struct device_info *info) { + int ret = 1; + VkApplicationInfo app_info = {0}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.pEngineName = "Engine"; @@ -124,24 +150,19 @@ static int create_instance(device_t device, struct device_info *info) char **extensions = xcalloc(info->ext_count+1, sizeof(char *)); extensions[info->ext_count] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; - for(uint32_t i = 0; i < info->ext_count; i++) { + for(u32 i = 0; i < info->ext_count; i++) { extensions[i] = (char *)info->extensions[i]; } - // we just added one more extension create_info.enabledExtensionCount = info->ext_count+1; create_info.ppEnabledExtensionNames = (const char * const *)extensions; // validation layer support - char *validation_layers[] = { - "VK_LAYER_KHRONOS_validation" - }; - - uint32_t nlayers = ARR_SIZE(validation_layers); + u32 nlayers = ARR_SIZE(validation_layers); - if(!has_validation_layer_support((const char * const *)validation_layers, nlayers)) { + if(!instance_has_validation_layers((const char * const *)validation_layers, nlayers)) { err("validation_layer_support: failed"); - goto fail; + goto exit; } create_info.ppEnabledLayerNames = (const char * const *)validation_layers; @@ -149,23 +170,25 @@ static int create_instance(device_t device, struct device_info *info) // add the debug messenger for instance creation and destruction VkDebugUtilsMessengerCreateInfoEXT msg_info = {0}; - populate_debug_messenger_info(&msg_info); + debug_messenger_populate_info(&msg_info); create_info.pNext = &msg_info; #endif if(vkCreateInstance(&create_info, NULL, &device->instance) != VK_SUCCESS) { err("vkCreateInstance: failed"); - goto fail; + goto exit; } + + + ret = 0; +exit: + #ifdef DEBUG free(extensions); #endif - - return 0; -fail: - return 1; + return ret; } static int create_surface(device_t device, struct device_info *info) @@ -181,22 +204,23 @@ static int create_surface(device_t device, struct device_info *info) static int create_physical_device(device_t device, struct device_info *info) { (void)info; + int ret = 1; device->physical_device = VK_NULL_HANDLE; - uint32_t dev_count = 0; + u32 dev_count = 0; vkEnumeratePhysicalDevices(device->instance, &dev_count, NULL); if(dev_count == 0) { err("No physical devices could be found!"); - goto fail; + goto exit; } VkPhysicalDevice *devices = xcalloc(dev_count, sizeof(VkPhysicalDevice)); vkEnumeratePhysicalDevices(device->instance, &dev_count, devices); - for(uint32_t i = 0; i < dev_count; i++) { - if(is_device_suitable(devices[i], device->surface)) { + for(u32 i = 0; i < dev_count; i++) { + if(device_is_suitable(devices[i], device->surface)) { device->physical_device = devices[i]; break; } @@ -206,39 +230,42 @@ static int create_physical_device(device_t device, struct device_info *info) if(device->physical_device == VK_NULL_HANDLE) { err("No suitable physical device could be found"); - goto fail; + goto exit; } - - return 0; -fail: - return 1; + + ret = 0; +exit: + return ret; } static int create_logical_device(device_t device, struct device_info *info) { (void)info; + int ret = 1; // queue family data struct queue_family_idx indices = {0}; - find_queue_families(device->physical_device, device->surface, &indices); + device_queue_families(device->physical_device, device->surface, &indices); // queue infos + #define QUEUE_FAMILY_COUNT 2 + VkDeviceQueueCreateInfo queue_infos[QUEUE_FAMILY_COUNT] = {0}; - uint32_t queue_indices[QUEUE_FAMILY_COUNT] = { + u32 queue_indices[QUEUE_FAMILY_COUNT] = { indices.graphics_family, indices.present_family, }; - uint32_t unique_queue_family_count = 0; + u32 unique_queue_family_count = 0; float queue_priority = 1.0f; // basically get add only the unique queue families - for(int i = 0; i < QUEUE_FAMILY_COUNT; i++) + for(size_t i = 0; i < QUEUE_FAMILY_COUNT; i++) { - int unique = 1; - for(int j = 0; j < i; j++) { + bool unique = true; + for(size_t j = 0; j < i; j++) { if(queue_indices[i] == queue_indices[j]) { - unique = 0; + unique = false; break; } } @@ -264,8 +291,9 @@ static int create_logical_device(device_t device, struct device_info *info) create_info.queueCreateInfoCount = unique_queue_family_count; create_info.pEnabledFeatures = &device_features; - - create_info.enabledExtensionCount = 0; + + create_info.ppEnabledExtensionNames = (const char * const *)device_extensions; + create_info.enabledExtensionCount = ARR_SIZE(device_extensions); // validation layers can be set, but // newer implementations will ignore them @@ -274,67 +302,241 @@ static int create_logical_device(device_t device, struct device_info *info) if(vkCreateDevice(device->physical_device, &create_info, NULL, &device->logical_device) != VK_SUCCESS) { err("vkCreateDevice: failed"); - goto fail; + goto exit; } - // vkGetDeviceQueue(device->logical_device, indices.graphics_family, 0, &device->graphics_queue); + vkGetDeviceQueue(device->logical_device, indices.graphics_family, 0, &device->graphics_queue); + vkGetDeviceQueue(device->logical_device, indices.present_family, 0, &device->present_queue); - return 0; -fail: - return 1; + ret = 0; +exit: + return ret; } -// returns a bitmask if a given family is set, or not -static int find_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family) +static int create_swap_chain(device_t device, struct device_info *info) { - int ret = 0; + (void)info; + int ret = 1; + + struct swap_chain_support_details details; + swap_chain_support(device->physical_device, device->surface, &details); + + VkSurfaceFormatKHR surface_format; + VkPresentModeKHR present_mode; + VkExtent2D extent; + u32 image_count = 3; - uint32_t count = 0; + swap_chain_choose_format(details.formats, details.nformats, &surface_format); + swap_chain_choose_present_mode(details.present_modes, details.npresent_modes, &present_mode); + swap_chain_get_extent(details.capabilities, &extent); + + if(details.capabilities.maxImageCount > 0) { + image_count = CLAMP(image_count, details.capabilities.minImageCount, details.capabilities.maxImageCount); + } + + // start filling in the create info + VkSwapchainCreateInfoKHR create_info = {0}; + create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + + create_info.surface = device->surface; + create_info.minImageCount = image_count; + create_info.imageFormat = surface_format.format; + create_info.imageColorSpace = surface_format.colorSpace; + create_info.imageExtent = extent; + create_info.imageArrayLayers = 1; + create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + struct queue_family_idx indices; + device_queue_families(device->physical_device, device->surface, &indices); + + u32 queue_indices[2] = { indices.graphics_family, indices.present_family }; + + // set the sharing mode of the images + if(indices.graphics_family != indices.present_family) { + create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + create_info.queueFamilyIndexCount = 2; + create_info.pQueueFamilyIndices = queue_indices; + } else { + create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + create_info.queueFamilyIndexCount = 0; + create_info.pQueueFamilyIndices = NULL; + } + + create_info.preTransform = details.capabilities.currentTransform; + create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + + create_info.presentMode = present_mode; + create_info.clipped = VK_TRUE; + + create_info.oldSwapchain = NULL; + + if (vkCreateSwapchainKHR(device->logical_device, &create_info, NULL, &device->swap_chain) != VK_SUCCESS) { + goto exit; + } + + vkGetSwapchainImagesKHR(device->logical_device, device->swap_chain, &device->nimages, NULL); + + device->swap_chain_images = xcalloc(device->nimages, sizeof(*device->swap_chain_images)); + vkGetSwapchainImagesKHR(device->logical_device, device->swap_chain, &device->nimages, device->swap_chain_images); + + ret = 0; +exit: + swap_chain_free_support_details(&details); + return ret; +} + +static int device_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family) +{ + u32 count = 0; vkGetPhysicalDeviceQueueFamilyProperties(phy_device, &count, NULL); VkQueueFamilyProperties *properties = xcalloc(count, sizeof(VkQueueFamilyProperties)); vkGetPhysicalDeviceQueueFamilyProperties(phy_device, &count, properties); - for(uint32_t i = 0; i < count; i++) { + for(u32 i = 0; i < count; i++) { if(properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - ret |= QUEUE_FAMILY_GRAPHICS_FAMILY; - if(queue_family != NULL) { - queue_family->graphics_family = i; - } + queue_family->graphics_family = i; + queue_family->has_graphics_family = true; } - VkBool32 present_support = 0; + VkBool32 present_support = false; vkGetPhysicalDeviceSurfaceSupportKHR(phy_device, i, surface, &present_support); + if(present_support) { - ret |= QUEUE_FAMILY_PRESENT_FAMILY; - if(queue_family != NULL){ - queue_family->present_family = i; - } + queue_family->present_family = i; + queue_family->has_present_family = true; } } free(properties); - return ret; + return 0; } -static int is_device_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface) +static bool device_is_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface) { - if(find_queue_families(phy_device, surface, NULL) == QUEUE_FAMILY_ALL) { - return 1; + struct queue_family_idx indices; + struct swap_chain_support_details details; + + return + (device_queue_families(phy_device, surface, &indices), + indices.has_graphics_family && indices.has_present_family) + && + (device_has_extension_support(phy_device)) + && + (swap_chain_support(phy_device, surface, &details), + swap_chain_free_support_details(&details), + (details.nformats > 0) && (details.npresent_modes > 0)); +} + +static bool device_has_extension_support(VkPhysicalDevice phy_device) +{ + u32 count = 0; + vkEnumerateDeviceExtensionProperties(phy_device, NULL, &count, NULL); + + VkExtensionProperties *properties = xcalloc(count, sizeof(VkExtensionProperties)); + vkEnumerateDeviceExtensionProperties(phy_device, NULL, &count, properties); + + for(size_t i = 0; i < ARR_SIZE(device_extensions); i++) + { + bool present = false; + for(u32 j = 0; j < count; j++) + if(strncmp(device_extensions[i], properties[j].extensionName, 256) == 0) { + present = true; + } + + if(!present) { + free(properties); + return false; + } } + + free(properties); + return true; +} + +static int swap_chain_support(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct swap_chain_support_details *details) +{ + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phy_device, surface, &details->capabilities); + + vkGetPhysicalDeviceSurfaceFormatsKHR(phy_device, surface, &details->nformats, NULL); + if(details->nformats > 0) { + details->formats = xcalloc(details->nformats, sizeof(*details->formats)); + vkGetPhysicalDeviceSurfaceFormatsKHR(phy_device, surface, &details->nformats, details->formats); + } + + vkGetPhysicalDeviceSurfacePresentModesKHR(phy_device, surface, &details->npresent_modes, NULL); + if(details->npresent_modes > 0) { + details->present_modes = xcalloc(details->npresent_modes, sizeof(*details->present_modes)); + vkGetPhysicalDeviceSurfacePresentModesKHR(phy_device, surface, &details->npresent_modes, details->present_modes); + } + + return 0; +} + +static void swap_chain_free_support_details(struct swap_chain_support_details *details) +{ + if(details->nformats > 0) free(details->formats); + if(details->npresent_modes > 0) free(details->present_modes); +} + +static int swap_chain_choose_format(VkSurfaceFormatKHR* formats, u32 nformats, VkSurfaceFormatKHR *format) +{ + for(u32 i = 0; i < nformats; i++) + if(formats[i].format == VK_FORMAT_B8G8R8A8_SRGB && + formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + *format = formats[i]; + return 0; + } + *format = formats[0]; return 0; } +static int swap_chain_choose_present_mode(VkPresentModeKHR *modes, u32 nmodes, VkPresentModeKHR *mode) +{ + for(u32 i = 0; i < nmodes; i++) + if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + *mode = modes[i]; + return 0; + } + + *mode = VK_PRESENT_MODE_FIFO_KHR; + return 0; +} + +static int swap_chain_get_extent(VkSurfaceCapabilitiesKHR capabilities, VkExtent2D *extent) +{ + if(capabilities.currentExtent.width != UINT32_MAX) { + *extent = capabilities.currentExtent; + return 0; + } + + // TODO implement + err("Not Implemented"); + return 1; +} #ifdef DEBUG +static bool instance_has_validation_layers(const char * const *layers, u32 nlayers) +{ + (void)layers; + (void)nlayers; + + // u32 navaliable = 0; + // vkEnumerateInstanceLayerProperties(&navaliable, NULL); + + // VkLayerProperties *available_layers = xcalloc(navaliable, sizeof(VkLayerProperties)); + // vkEnumerateInstanceLayerProperties(&navaliable, available_layers); + return true; +} + static int create_debug_messenger(device_t device, struct device_info *info) { (void)info; VkDebugUtilsMessengerCreateInfoEXT cinfo = {0}; - populate_debug_messenger_info(&cinfo); + debug_messenger_populate_info(&cinfo); if(CreateDebugUtilsMessengerEXT(device->instance, &cinfo, NULL, &device->debug_messenger) != VK_SUCCESS) { info("CreateDebugUtilMessengerEXT: failed"); @@ -344,7 +546,7 @@ static int create_debug_messenger(device_t device, struct device_info *info) return 0; } -static void populate_debug_messenger_info(VkDebugUtilsMessengerCreateInfoEXT *info) +static void debug_messenger_populate_info(VkDebugUtilsMessengerCreateInfoEXT *info) { info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; info->messageSeverity = @@ -355,23 +557,10 @@ static void populate_debug_messenger_info(VkDebugUtilsMessengerCreateInfoEXT *in VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - info->pfnUserCallback = debug_callback; -} - -static int has_validation_layer_support(const char * const *layers, uint32_t nlayers) -{ - (void)layers; - (void)nlayers; - - // uint32_t navaliable = 0; - // vkEnumerateInstanceLayerProperties(&navaliable, NULL); - - // VkLayerProperties *available_layers = xcalloc(navaliable, sizeof(VkLayerProperties)); - // vkEnumerateInstanceLayerProperties(&navaliable, available_layers); - return 1; + info->pfnUserCallback = debug_messenger_callback; } -static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( +static VKAPI_ATTR VkBool32 VKAPI_CALL debug_messenger_callback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, diff --git a/src/device.h b/src/device.h index d6768e1..3491b8a 100644 --- a/src/device.h +++ b/src/device.h @@ -1,9 +1,18 @@ #ifndef DEVICE_H #define DEVICE_H +#include <stdint.h> +#include <stdbool.h> #include <vulkan/vulkan.h> + #include "common.h" +// from vulkan source +#define MAKE_VERSION(major, minor, patch) \ + ((((u32)(major)) << 22U) | (((u32)(minor)) << 12U) | ((u32)(patch))) + +typedef uint32_t u32; + typedef struct device { VkInstance instance; VkDebugUtilsMessengerEXT debug_messenger; @@ -11,20 +20,23 @@ typedef struct device { VkPhysicalDevice physical_device; VkDevice logical_device; VkQueue graphics_queue; + VkQueue present_queue; + VkSwapchainKHR swap_chain; VkSurfaceKHR surface; -} * device_t; -typedef int (*surface_func_t)(VkInstance instance, VkSurfaceKHR *surface); + VkImage *swap_chain_images; + u32 nimages; +} * device_t; struct device_info { char *name; - uint32_t version; + u32 version; const char* const* extensions; - uint32_t ext_count; + u32 ext_count; - surface_func_t surface_func; + int (*surface_func)(VkInstance instance, VkSurfaceKHR *surface); }; device_t device_create(struct device_info *info); @@ -1,13 +1,11 @@ #include <stdio.h> #include <stdlib.h> -#include <stdint.h> #include "device.h" #include "window.h" #include "common.h" // TODO: rename device.c/.h -// TODO: fix fail gotos window_t window; device_t device; @@ -20,7 +18,7 @@ int main(void) if(SDL_Init(0)) { err("SDL_Init: failed"); - goto sf; + goto f1; } // populate window info @@ -33,7 +31,7 @@ int main(void) window = window_create(&win_info); if(!window) { err("window_create: failed"); - goto wf; + goto f2; } // get extensions @@ -57,7 +55,8 @@ int main(void) device = device_create(&dev_info); if(!device) { err("device_create: failed"); - goto df; + if(extensions) free(extensions); + goto f3; } if(extensions) free(extensions); @@ -73,10 +72,11 @@ int main(void) } ret = 0; -df: device_destroy(device); -wf: window_destroy(window); -sf: SDL_Quit(); - return ret; + + device_destroy(device); +f3: window_destroy(window); +f2: SDL_Quit(); +f1: return ret; } int _create_surface(VkInstance instance, VkSurfaceKHR *surface) |