From 39d7d87be2eb32c9a25f2b85ba9288e0e590a2ad Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Sat, 2 Nov 2019 02:52:13 -0500 Subject: Get absolute minimum working --- main.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 125 insertions(+), 52 deletions(-) diff --git a/main.c b/main.c index 77b2d3b..68b43aa 100644 --- a/main.c +++ b/main.c @@ -124,16 +124,23 @@ struct SwapchainVulkan { VkImageView *imageViews; }; -/** Vulkan application that uses Pugl for windows and events */ +/** Vulkan application that uses Pugl for windows and events + * + * TODO: Separate Instance from rest of application. + * All Pugl stuff must be destroyed AFTER freeing the surface but BEFORE + * freeing the instance. Right now we are forced to destroy them inside of + * `rvkDestroy` even though the user creates them. + */ struct RenderVulkan { struct VulkanAPI *api; struct VulkanDev *dev; PuglWorld *world; + PuglView *view; char *errMsg; VkInstance instance; VkDebugReportCallbackEXT debugCallback; VkSurfaceKHR surface; - VkPhysicalDeviceProperties deviceProperties; + VkPhysicalDeviceProperties deviceProperties; // TODO: Put this on the heap VkPhysicalDevice physicalDevice; uint32_t graphicsIndex; VkDevice device; @@ -1025,23 +1032,6 @@ int rvkOpenDevice(struct RenderVulkan *vk) return 0; } -static void rvkCloseDevice(struct RenderVulkan *vk) -{ - if (vk->commandPool) { - vk->dev->vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); - vk->commandPool = VK_NULL_HANDLE; - } - vk->graphicsQueue = VK_NULL_HANDLE; - if (vk->dev->vkDestroyDevice) { - vk->dev->vkDestroyDevice(vk->device, ALLOC_VK); - } else { - fprintf(stderr, "Fatal: Unable to destroy logical device (missing function pointer)\n"); - } - free(vk->dev); - vk->dev = NULL; - vk->device = VK_NULL_HANDLE; -} - static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height) { VkSurfaceCapabilitiesKHR surfaceCapabilities; @@ -1119,20 +1109,28 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height) static void rvkDestroyRawSwapchain(struct RenderVulkan *vk) { - vk->dev->vkDestroySwapchainKHR(vk->device, vk->swapchain.rawSwapchain, ALLOC_VK); - memset(&vk->swapchain.surfaceFormat, 0, sizeof(vk->swapchain.surfaceFormat)); - memset(&vk->swapchain, 0, sizeof(vk->swapchain)); + if (vk->swapchain.rawSwapchain) { + vk->dev->vkDestroySwapchainKHR(vk->device, vk->swapchain.rawSwapchain, ALLOC_VK); + memset(&vk->swapchain.surfaceFormat, 0, sizeof(vk->swapchain.surfaceFormat)); + memset(&vk->swapchain, 0, sizeof(vk->swapchain)); + } } static VkResult createSwapchainImageViews(VkDevice device, const struct VulkanDev *const dev, struct SwapchainVulkan *const swapchain) { - dev->vkGetSwapchainImagesKHR(device, swapchain->rawSwapchain, &swapchain->nImages, NULL); + VkResult result; + if ((result = dev->vkGetSwapchainImagesKHR(device, swapchain->rawSwapchain, &swapchain->nImages, NULL))) { + return result; + } swapchain->images = calloc(swapchain->nImages, sizeof(*swapchain->images)); - dev->vkGetSwapchainImagesKHR(device, swapchain->rawSwapchain, &swapchain->nImages, swapchain->images); - //swapchain->imageViews = calloc(swapchain->nImages, sizeof(*swapchain->imageViews)); + if ((result = dev->vkGetSwapchainImagesKHR(device, swapchain->rawSwapchain, &swapchain->nImages, swapchain->images))) { + return result; + } +#if 0 + /* We don't need this yet until we start using as a render target. */ + swapchain->imageViews = calloc(swapchain->nImages, sizeof(*swapchain->imageViews)); - VkResult result; for (uint32_t i = 0; i < swapchain->nImages; ++i) { VkImageViewCreateInfo createInfo = { 0 }; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -1148,23 +1146,34 @@ static VkResult createSwapchainImageViews(VkDevice device, createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; - // if ((result = dev->vkCreateImageView(device, &createInfo, ALLOC_VK, &swapchain->imageViews[i]))) { - // return result; - // } + if ((result = dev->vkCreateImageView(device, &createInfo, ALLOC_VK, &swapchain->imageViews[i]))) { + return result; + } } +#endif return VK_SUCCESS; } static void destroySwapchainImageViews(VkDevice device, - const struct VulkanDev *const dev, struct SwapchainVulkan *const swapchain) + const struct VulkanDev *const dev, + struct SwapchainVulkan *const swapchain) { - for (uint32_t i = 0; i < swapchain->nImages; ++i) { - dev->vkDestroyImageView(device, swapchain->imageViews[i], ALLOC_VK); + if (swapchain->imageViews) { + for (uint32_t i = 0; i < swapchain->nImages; ++i) { + if (swapchain->imageViews[i]) { + dev->vkDestroyImageView(device, + swapchain->imageViews[i], + ALLOC_VK); + } + } + free(swapchain->imageViews); + swapchain->imageViews = NULL; + } + if (swapchain->images) { + free(swapchain->images); + swapchain->images = NULL; + swapchain->nImages = 0; } - free(swapchain->imageViews); - free(swapchain->images); - swapchain->imageViews = NULL; - swapchain->images = NULL; } static VkResult allocateCommandBuffers(struct RenderVulkan *vk) @@ -1180,9 +1189,14 @@ static VkResult allocateCommandBuffers(struct RenderVulkan *vk) static void freeCommandBuffers(struct RenderVulkan *vk) { - vk->dev->vkFreeCommandBuffers(vk->device, vk->commandPool, vk->swapchain.nImages, vk->commandBuffers); - free(vk->commandBuffers); - vk->commandBuffers = NULL; + if (vk->commandBuffers) { + vk->dev->vkFreeCommandBuffers(vk->device, + vk->commandPool, + vk->swapchain.nImages, + vk->commandBuffers); + free(vk->commandBuffers); + vk->commandBuffers = NULL; + } } static int recordCommandBuffers(struct RenderVulkan *vk) @@ -1270,6 +1284,13 @@ int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int heigh return 0; } +void rvkDestroySwapchain(struct RenderVulkan *vk) +{ + freeCommandBuffers(vk); + destroySwapchainImageViews(vk->device, vk->dev, &vk->swapchain); + rvkDestroyRawSwapchain(vk); +} + /** Creates any semaphores or fences for this application. */ int rvkCreateSyncObjects(struct RenderVulkan *vk) { @@ -1280,27 +1301,82 @@ int rvkCreateSyncObjects(struct RenderVulkan *vk) return 0; } +void rvkDestroySyncObjects(struct RenderVulkan *vk) +{ + if (vk->sync.semaphore.renderFinished) { + vk->dev->vkDestroySemaphore(vk->device, vk->sync.semaphore.renderFinished, ALLOC_VK); + vk->sync.semaphore.renderFinished = VK_NULL_HANDLE; + } + if (vk->sync.semaphore.imageAvailable) { + vk->dev->vkDestroySemaphore(vk->device, vk->sync.semaphore.imageAvailable, ALLOC_VK); + vk->sync.semaphore.imageAvailable = VK_NULL_HANDLE; + } +} + +static void rvkCloseDevice(struct RenderVulkan *vk) +{ + if (vk->device) { + if (vk->dev->vkDeviceWaitIdle) vk->dev->vkDeviceWaitIdle(vk->device); + rvkDestroySyncObjects(vk); + rvkDestroySwapchain(vk); + if (vk->commandPool) { + vk->dev->vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); + vk->commandPool = VK_NULL_HANDLE; + } + vk->graphicsQueue = VK_NULL_HANDLE; + /* `vk->device` implies `vk->dev` but device functions MAY not + * be loaded. + * However, all subobjects of `vk->device` imply functions loaded + */ + if (vk->dev->vkDestroyDevice) { + vk->dev->vkDestroyDevice(vk->device, ALLOC_VK); + } else { + /* This is only theoretical, because we must load the "destroy" + * function *after* we create the device + */ + fprintf(stderr, "Fatal: Unable to destroy logical device (missing function pointer)\n"); + } + free(vk->dev); + vk->dev = NULL; + vk->device = VK_NULL_HANDLE; + } +} + /** This must work no matter the current state of `vk` */ void rvkDestroy(struct RenderVulkan *vk) { if (vk) { - /* `vk->device` implies `vk->dev` but device functions MAY not be loaded */ - if (vk->device) { - if (vk->dev->vkDeviceWaitIdle) vk->dev->vkDeviceWaitIdle(vk->device); - rvkDestroyRawSwapchain(vk); - rvkCloseDevice(vk); + rvkCloseDevice(vk); + if (vk->surface) { + vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); + vk->surface = VK_NULL_HANDLE; + } + /* PuglView must be freed AFTER surface but BEFORE instance destroy */ + if (vk->view) { + puglFreeView(vk->view); + vk->view = NULL; } - if (vk->surface) vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); if (vk->debugCallback) { /* `vk->debugCallback` implies `vk->api` and all instance functions loaded */ vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK); + vk->debugCallback = VK_NULL_HANDLE; + } + /* PuglWorld must be unloaded AFTER PuglView but BEFORE instance destroy */ + puglFreeWorld(vk->world); + vk->world = NULL; + if (vk->instance) { + rvkDestroyInstance(vk); + vk->instance = VK_NULL_HANDLE; } - if (vk->instance) rvkDestroyInstance(vk); if (vk->api) { if (vk->api->handle) unloadVulkanLibrary(vk->api->handle); free(vk->api); + vk->api = NULL; + } + if (vk->errMsg) { + free(vk->errMsg); + vk->errMsg = NULL; } - if (vk->errMsg) free(vk->errMsg); free(vk); } } @@ -1402,7 +1478,6 @@ int main() CHECK_RVK(vk, rvkCreate(world, &vk)); printf("Created Vulkan Instance Successfully\n"); - PuglView *view = puglNewView(world); const PuglRect frame = { 0, 0, 800, 600 }; puglSetFrame(view, frame); @@ -1414,7 +1489,7 @@ int main() fprintf(stderr, "Could not create window: %d\n", status); rvkFatal(vk); } - puglSetEventFunc(view, onEvent); + vk->view = view; CHECK_RVK(vk, rvkCreateSurface(vk, view)); CHECK_RVK(vk, rvkSelectPhysicalDevice(vk)); @@ -1424,15 +1499,13 @@ int main() printf("Opened Vulkan Device Successfully\n"); + puglSetEventFunc(view, onEvent); puglShowWindow(view); while (running) { puglPollEvents(world, -1); puglDispatchEvents(world); } - puglFreeView(view); - 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