From 9e3b1faeddacb78d342ae630815cb19030846a6f Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Thu, 7 Nov 2019 23:55:37 -0600 Subject: Support manually collecting swapchain garbage --- main.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/main.c b/main.c index e0debb0..794a0dd 100755 --- a/main.c +++ b/main.c @@ -187,7 +187,7 @@ struct VulkanDev { /** Application-specific swapchain behavior */ struct SwapchainVulkan { - struct SwapchainVulkan *pNext; // Linked list of retired swapchains + struct SwapchainVulkan *old; // Linked list of retired swapchains VkSwapchainKHR rawSwapchain; uint32_t nImages; VkExtent2D extent; @@ -1321,7 +1321,7 @@ int rvkConfigureSurface(struct RenderVulkan *vk) return 0; } -static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height) +static int rvkCreateRawSwapchain(struct RenderVulkan *vk, uint32_t width, uint32_t height) { // FIXME: We actually need a new surfaceCapabilities for every new swapchain. //width = CLAMP(width, vk->surfaceCapabilities.minImageExtent.width, vk->surfaceCapabilities.maxImageExtent.width); @@ -1346,8 +1346,8 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height) createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.presentMode = vk->presentMode; createInfo.clipped = VK_TRUE; - if (vk->swapchain->pNext) { - createInfo.oldSwapchain = vk->swapchain->pNext->rawSwapchain; + if (vk->swapchain->old) { + createInfo.oldSwapchain = vk->swapchain->old->rawSwapchain; } VkResult result; if ((result = vk->dev->vkCreateSwapchainKHR(vk->device, &createInfo, ALLOC_VK, &vk->swapchain->rawSwapchain))) { @@ -1512,11 +1512,11 @@ static int recordCommandBuffers(struct RenderVulkan *vk) return 0; } -int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int height) +int rvkCreateSwapchain(struct RenderVulkan *vk, const uint32_t width, const uint32_t height) { struct SwapchainVulkan *oldSwapchain = vk->swapchain; vk->swapchain = calloc(1, sizeof(*vk->swapchain)); - vk->swapchain->pNext = oldSwapchain; + vk->swapchain->old = oldSwapchain; if (rvkCreateRawSwapchain(vk, width, height)) { return -1; } @@ -1546,7 +1546,7 @@ int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int heigh } // TODO: Move device into RenderDev to limit scope -void rvkDestroySwapchain(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain) +static void rvkDestroySwapchain(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain) { if (swapchain && swapchain->fences) { for (uint32_t i = 0; i < swapchain->nImages; ++i) { @@ -1564,12 +1564,43 @@ void rvkDestroySwapchain(struct RenderVulkan *vk, struct SwapchainVulkan *swapch free(swapchain); } -// TODO: Destroy retired swapchains during rendering; not just all at once at destroy time. +static bool canDestroySwapchain(const struct RenderVulkan *vk, + const struct SwapchainVulkan *swapchain) +{ + uint32_t notReady = 0; + for (uint32_t i = 0; i < swapchain->nImages; ++i) { + VkResult result; + result = vk->dev->vkGetFenceStatus(vk->device, swapchain->fences[i]); + if (result == VK_NOT_READY) { + ++notReady; + } + } + return !notReady; +} + +/* FIXME: Race condition! Swapchains cannot be destroyed until they are done + * being rendered to. + */ +void rvkCollectSwapchainGarbage(struct RenderVulkan *vk) +{ + struct SwapchainVulkan *old, *pp = vk->swapchain; + uint32_t count = 0; + if (pp && (pp)->old) { + for(pp = (pp)->old; pp; pp = old) { + old = (pp)->old; + rvkDestroySwapchain(vk, pp); + ++count; + } + vk->swapchain->old = NULL; + } + printf("Collected %d retired swapchains\n", count); +} + void rvkDestroyAllSwapchains(struct RenderVulkan *vk) { - struct SwapchainVulkan *swapchain, *pNext; - for (swapchain = vk->swapchain; swapchain; swapchain = pNext) { - pNext = swapchain->pNext; + struct SwapchainVulkan *swapchain, *old; + for (swapchain = vk->swapchain; swapchain; swapchain = old) { + old = swapchain->old; rvkDestroySwapchain(vk, swapchain); } } @@ -1601,7 +1632,6 @@ static void rvkCloseDevice(struct RenderVulkan *vk) if (vk->device) { if (vk->dev->vkDeviceWaitIdle) vk->dev->vkDeviceWaitIdle(vk->device); rvkDestroySyncObjects(vk); - //rvkDestroySwapchain(vk); rvkDestroyAllSwapchains(vk); if (vk->commandPool) { vk->dev->vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); @@ -1696,6 +1726,18 @@ struct Arguments args; uint32_t framesDrawn; +static bool shouldResize(const struct RenderVulkan *vk, const PuglEvent *e) +{ + const struct SwapchainVulkan *swapchain = vk->swapchain; + return (swapchain->extent.width != e->configure.width) || + (swapchain->extent.height != e->configure.height); +} + +static PuglStatus onResize(struct RenderVulkan *vk, uint32_t width, uint32_t height) +{ + CHECK_RVK(vk, rvkCreateSwapchain(vk, width, height)); +} + PuglStatus onDisplay(PuglView *view) { struct RenderVulkan *vk = puglGetHandle(view); @@ -1716,6 +1758,7 @@ PuglStatus onDisplay(PuglView *view) break; case VK_SUBOPTIMAL_KHR: case VK_ERROR_OUT_OF_DATE_KHR: + printf("Reactive resize!\n"); frame = puglGetFrame(vk->view); CHECK_RVK(vk, rvkCreateSwapchain(vk, frame.width, frame.height)); continue; @@ -1775,20 +1818,36 @@ PuglStatus onDisplay(PuglView *view) PuglStatus onEvent(PuglView *view, const PuglEvent *e) { printEvent(e, "Event:\t", args.verbose); + struct RenderVulkan *vk = puglGetHandle(view); switch (e->type) { - case PUGL_EXPOSE: - onDisplay(view); - break; - case PUGL_CLOSE: + case PUGL_EXPOSE: + return onDisplay(view); + break; + case PUGL_CONFIGURE: + // Proactive resize + if (shouldResize(vk, e)) { + return onResize(vk, + e->configure.width, + e->configure.height); + } + break; + case PUGL_CLOSE: + running = 0; + break; + case PUGL_KEY_PRESS: + switch (e->key.key) { + case PUGL_KEY_ESCAPE: running = 0; break; - case PUGL_KEY_PRESS: - if (e->key.key == PUGL_KEY_ESCAPE) { - running = 0; - } - break; - default: + case 'c': + // Manually collect swapchain garbage + vk->dev->vkDeviceWaitIdle(vk->device); + rvkCollectSwapchainGarbage(vk); break; + } + break; + default: + break; } return PUGL_SUCCESS; } -- cgit v1.2.1