From 17ccf0a4d484806e191d4c76ed7ffac90d2fa7b5 Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Wed, 30 Oct 2019 20:28:09 -0500 Subject: Refactor error handling --- main.c | 117 ++++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/main.c b/main.c index e0d2451..fd2d74d 100644 --- a/main.c +++ b/main.c @@ -312,7 +312,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( return VK_FALSE; } -static VkResult createInstance(struct RenderVulkan *vk, +static VkResult rvkCreateInstance(struct RenderVulkan *vk, const uint32_t nLayers, const char *const *const layers, const uint32_t nAdditional, const char *const *const additionalExtensions) { @@ -361,7 +361,7 @@ static VkResult createInstance(struct RenderVulkan *vk, } /** Must not be called until all derivative objects are destroyed first */ -static void destroyInstance(struct RenderVulkan *vk) +static void rvkDestroyInstance(struct RenderVulkan *vk) { vk->api->vkDestroyInstance(vk->instance, ALLOC_VK); vk->instance = VK_NULL_HANDLE; @@ -371,18 +371,21 @@ static void destroyInstance(struct RenderVulkan *vk) void rvkDestroy(struct RenderVulkan *vk) { if (vk) { + // TODO + // /* `vk->device` implies `vk->dev` and all device functions loaded */ + // if (vk->device) vk->dev->vkDeviceWaitIdle(vk->device); if (vk->surface) vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); if (vk->debugCallback) { - /* `vk->debugCallback` implies `vk->api` and instance functions loaded */ + /* `vk->debugCallback` implies `vk->api` and all instance functions loaded */ vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK); } - if (vk->instance) destroyInstance(vk); + if (vk->instance) rvkDestroyInstance(vk); if (vk->api) { if (vk->api->handle) unloadVulkanLibrary(vk->api->handle); free(vk->api); } if (vk->errMsg) free(vk->errMsg); - if (vk) free(vk); + free(vk); } } @@ -405,7 +408,7 @@ void rvkDestroy(struct RenderVulkan *vk) * and MUST be checked via `rvkGetErrMsg`. It MUST then be destroyed via * `rvkDestroy`. * */ -struct RenderVulkan *rvkCreate(PuglWorld *world) +int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut) { static const char *const instanceLayers[] = { "VK_LAYER_LUNARG_standard_validation" @@ -419,7 +422,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) struct RenderVulkan *vk = calloc(1, sizeof(*vk)); if (!world) { rvkSetErrMsg(vk, "No PuglWorld provided"); - return vk; + return -1; } vk->world = world; vk->api = calloc(1, sizeof(*vk->api)); @@ -427,26 +430,26 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) vk->api->handle = loadVulkanLibrary(NULL); if (!vk->api->handle) { rvkSetErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror()); - return vk; + return -1; } loadVulkanGetInstanceProcAddrFunc(vk->api->handle, &vk->api->vkGetInstanceProcAddr); if (!vk->api->vkGetInstanceProcAddr) { rvkSetErrMsg(vk, "Error loading `vkGetInstanceProcAddr`:\n%s", appDlerror()); - return vk; + return -1; } uintptr_t *const ulCreateInstance = (uintptr_t*)&vk->api->vkCreateInstance; *ulCreateInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(NULL, "vkCreateInstance"); if (!vk->api->vkCreateInstance) { rvkSetErrMsg(vk, "Error loading `vkCreateInstance`"); - return vk; + return -1; } VkResult result; - //if ((result = createInstance(vk, 0, NULL, 0, NULL))) { - if ((result = createInstance(vk, nInstanceLayers, instanceLayers, nInstanceExtensions, instanceExtensions))) { - return vk; + //if ((result = rvkCreateInstance(vk, 0, NULL, 0, NULL))) { + if ((result = rvkCreateInstance(vk, nInstanceLayers, instanceLayers, nInstanceExtensions, instanceExtensions))) { + return -1; } static const char *const strErrLd = "Error loading function %s"; @@ -456,7 +459,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulDestroyInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroyInstance); if (!vk->api->vkDestroyInstance) { rvkSetErrMsg(vk, strErrLd, strDestroyInstance); - return vk; + return -1; } /* It is okay if debug reporter functions are not resolved (for now) */ @@ -469,7 +472,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) /* But not if we are unable to destroy a created debug reporter */ if (vk->api->vkCreateDebugReportCallbackEXT && !vk->api->vkDestroyDebugReportCallbackEXT) { rvkSetErrMsg(vk, "No debug reporter destroy function loaded for corresponding create function\n"); - return vk; + return -1; } /* Dynamically load instance-level Vulkan function pointers via `vkGetInstanceProcAddr` @@ -483,7 +486,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulDestroySurfaceKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroySurfaceKHR); if (!vk->api->vkDestroySurfaceKHR) { rvkSetErrMsg(vk, strErrLd, strDestroySurfaceKHR); - return vk; + return -1; } static const char *const strEnumeratePhysicalDevices = "vkEnumeratePhysicalDevices"; @@ -491,7 +494,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulEnumeratePhysicalDevices = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumeratePhysicalDevices); if (!vk->api->vkEnumeratePhysicalDevices) { rvkSetErrMsg(vk, strErrLd, strEnumeratePhysicalDevices); - return vk; + return -1; } static const char *const strGetPhysicalDeviceProperties = "vkGetPhysicalDeviceProperties"; @@ -499,7 +502,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulGetPhysicalDeviceProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceProperties); if (!vk->api->vkGetPhysicalDeviceProperties) { rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceProperties); - return vk; + return -1; } static const char *const strGetPhysicalDeviceQueueFamilyProperties = "vkGetPhysicalDeviceQueueFamilyProperties"; @@ -507,7 +510,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulGetPhysicalDeviceQueueFamilyProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceQueueFamilyProperties); if (!vk->api->vkGetPhysicalDeviceQueueFamilyProperties) { rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceQueueFamilyProperties); - return vk; + return -1; } static const char *const strGetPhysicalDeviceSurfaceSupportKHR = "vkGetPhysicalDeviceSurfaceSupportKHR"; @@ -515,7 +518,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulGetPhysicalDeviceSurfaceSupportKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceSurfaceSupportKHR); if (!vk->api->vkGetPhysicalDeviceSurfaceSupportKHR) { rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceSurfaceSupportKHR); - return vk; + return -1; } static const char *const strGetPhysicalDeviceMemoryProperties = "vkGetPhysicalDeviceMemoryProperties"; @@ -523,7 +526,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulGetPhysicalDeviceMemoryProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceMemoryProperties); if (!vk->api->vkGetPhysicalDeviceMemoryProperties) { rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceMemoryProperties); - return vk; + return -1; } static const char *const strEnumerateDeviceExtensionProperties = "vkEnumerateDeviceExtensionProperties"; @@ -531,7 +534,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) *ulEnumerateDeviceExtensionProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumerateDeviceExtensionProperties); if (!vk->api->vkEnumerateDeviceExtensionProperties) { rvkSetErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties); - return vk; + return -1; } /* End loading function pointers */ @@ -543,19 +546,22 @@ struct RenderVulkan *rvkCreate(PuglWorld *world) if ((result = vk->api->vkCreateDebugReportCallbackEXT(vk->instance, &debugInfo, ALLOC_VK, &vk->debugCallback))) { rvkSetErrMsg(vk, "Could not create debug reporter: %d", result); - return vk; + return -1; } } - return vk; + *vkOut = vk; + return 0; } -static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view) +static int rvkCreateSurface(struct RenderVulkan *vk, PuglView *view) { VkResult result; if ((result = createVulkanSurface(view, vk->instance, vk->api->vkGetInstanceProcAddr, ALLOC_VK, &vk->surface))) { rvkSetErrMsg(vk, "Could not create window surface: %d\n", result); + return -1; } + return 0; } /** Checks if a particular physical device is suitable for this application. @@ -606,7 +612,7 @@ static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view) * Information for many devices is available online at * https://vulkan.gpuinfo.org/ */ -static int rvkIsDeviceSuitable(const struct RenderVulkan *const vk, +static bool rvkIsDeviceSuitable(const struct RenderVulkan *const vk, const VkPhysicalDevice physicalDevice, uint32_t *const graphicsIndex) { @@ -629,26 +635,26 @@ static int rvkIsDeviceSuitable(const struct RenderVulkan *const vk, if (g >= nQueueFamilies) { /* We only support graphics and present on the same queue family. */ printf("No graphics+support queue families found on this device\n"); - return 0; + return false; } - VkBool32 canSwapchain = 0; + VkBool32 canSwapchain = VK_FALSE; uint32_t nExtensions; vk->api->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, NULL); VkExtensionProperties *availableExtensions = malloc(nExtensions * sizeof(*availableExtensions)); vk->api->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, availableExtensions); for (uint32_t i = 0; i < nExtensions; ++i) { if (!strcmp(availableExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { - canSwapchain = 1; + canSwapchain = VK_TRUE; break; } } free(availableExtensions); if (!canSwapchain) { printf("Cannot use a swapchain on this device\n"); - return 0; + return false; } *graphicsIndex = g; - return 1; + return true; } /** Selects a physical device @@ -656,11 +662,12 @@ static int rvkIsDeviceSuitable(const struct RenderVulkan *const vk, * This application will not attempt to find the "most powerful" device on the * system, and will choose the first suitable device it finds. */ -void rvkSelectPhysicalDevice(struct RenderVulkan *vk) +int rvkSelectPhysicalDevice(struct RenderVulkan *vk) { + int ret = 0; if (!vk->surface) { rvkSetErrMsg(vk, "Cannot select a physical device without a surface"); - return; + return -1; } static const char *const strErrEnum = "Could not enumerate physical devices: %s"; static const char *const strWarnEnum = "Warn: Incomplete enumeration of physical devices"; @@ -669,20 +676,21 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk) if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) { if (result != VK_INCOMPLETE) { rvkSetErrMsg(vk, strErrEnum, result); - return; + return -1; } else { fprintf(stderr, "%s\n", strWarnEnum); } } if (!nDevices) { rvkSetErrMsg(vk, "No physical devices found"); - return; + return -1; } VkPhysicalDevice *devices = malloc(nDevices * sizeof(*devices)); VkPhysicalDeviceProperties *deviceProperties = malloc(nDevices * sizeof(*deviceProperties)); if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) { if (result != VK_INCOMPLETE) { rvkSetErrMsg(vk, strErrEnum, result); + ret = -1; goto done; } else { fprintf(stderr, "%s\n", strWarnEnum); @@ -709,22 +717,32 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk) } if (i >= nDevices) { rvkSetErrMsg(vk, "No suitable devices found"); + ret = -1; } done: free(deviceProperties); free(devices); + return ret; } -void rvkCheckFatal(struct RenderVulkan *vk) +/* Normally, we would NOT exit the entire process on errors when running as + * part of a larger process, but since we own this process, there isn't anything + * else to do. As a plugin, we would destroy the window and all memory + * associated with it, leaving the larger process intact. + */ +static void rvkFatal(struct RenderVulkan *vk) { - const char *errMsg = NULL; - if ((errMsg = rvkGetErrMsg(vk))) { - fprintf(stderr, "%s\n", errMsg); - rvkDestroy(vk); - exit(1); + fprintf(stderr, "%s\n", rvkGetErrMsg(vk)); + rvkDestroy(vk); + if (vk->world) { + puglFreeWorld(vk->world); } + printf("Aborting gracefully\n"); + exit(1); } +#define CHECK_RVK(rvk, expr) do { if ((expr)) { rvkFatal(rvk); } } while (0) + int running = 1; PuglStatus onEvent(PuglView *view, const PuglEvent *e) @@ -747,11 +765,10 @@ int main() XInitThreads(); #endif PuglWorld *world = puglNewWorld(); - const char *errMsg = NULL; /** Vulkan application that uses Pugl for windows and events */ - struct RenderVulkan *vk = rvkCreate(world); - rvkCheckFatal(vk); + struct RenderVulkan *vk = NULL; + CHECK_RVK(vk, rvkCreate(world, &vk)); printf("Created Vulkan Instance Successfully\n"); @@ -762,17 +779,12 @@ int main() PuglStatus status; if ((status = puglCreateWindow(view, "Vulkan Application Using Pugl"))) { fprintf(stderr, "Could not create window: %d\n", status); - rvkDestroy(vk); - puglFreeWorld(world); - exit(1); + rvkFatal(vk); } puglSetEventFunc(view, onEvent); - rvkCreateSurface(vk, view); - rvkCheckFatal(vk); - - rvkSelectPhysicalDevice(vk); - rvkCheckFatal(vk); + CHECK_RVK(vk, rvkCreateSurface(vk, view)); + CHECK_RVK(vk, rvkSelectPhysicalDevice(vk)); puglShowWindow(view); while (running) { @@ -784,6 +796,7 @@ int main() puglFreeWorld(world); /* Vulkan library MUST be unloaded AFTER call to XCloseDisplay() or it will segfault */ rvkDestroy(vk); + printf("Exiting gracefully\n"); return 0; } -- cgit v1.2.1