From 92ae03a9c8783bc224e8ffd1bb675d648c33b460 Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Thu, 7 Nov 2019 16:07:31 -0600 Subject: Begin adding swapchain recreation support --- main.c | 109 +++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 40 deletions(-) diff --git a/main.c b/main.c index 2a7f242..e0debb0 100755 --- a/main.c +++ b/main.c @@ -60,6 +60,10 @@ PERFORMANCE OF THIS SOFTWARE. #define APP_THREAD_LOCAL __declspec(thread) #endif +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define CLAMP(x, l, h) ((x) <= (l) ? (l) : (x) >= (h) ? (h) : (x)) + struct Arguments { bool validation; bool verbose; @@ -190,6 +194,7 @@ struct SwapchainVulkan { VkImage *images; VkImageView *imageViews; VkFence *fences; + VkCommandBuffer *commandBuffers; }; struct SemaphoreVulkan { @@ -228,7 +233,6 @@ struct RenderVulkan { VkQueue graphicsQueue; VkCommandPool commandPool; struct SwapchainVulkan *swapchain; - VkCommandBuffer *commandBuffers; struct SyncVulkan sync; }; @@ -720,6 +724,7 @@ int rvkCreateSurface(struct RenderVulkan *vk, const PuglRect frame) puglSetFrame(vk->view, frame); puglSetHandle(vk->view, vk); puglSetBackend(vk->view, puglStubBackend()); + puglSetViewHint(vk->view, PUGL_RESIZABLE, true); PuglStatus status; if ((status = puglCreateWindow(vk->view, "Vulkan Application Using Pugl"))) { @@ -1318,15 +1323,16 @@ int rvkConfigureSurface(struct RenderVulkan *vk) static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height) { - // TODO: Clamp + // FIXME: We actually need a new surfaceCapabilities for every new swapchain. + //width = CLAMP(width, vk->surfaceCapabilities.minImageExtent.width, vk->surfaceCapabilities.maxImageExtent.width); + //height = CLAMP(height, vk->surfaceCapabilities.minImageExtent.height, vk->surfaceCapabilities.maxImageExtent.height); + vk->swapchain->extent.width = width; vk->swapchain->extent.height = height; vk->swapchain->nImages = vk->surfaceCapabilities.minImageCount; //vk->swapchain->nImages = vk->surfaceCapabilities.maxImageCount; - printf("Using %d swapchain images\n", vk->swapchain->nImages); - VkSwapchainCreateInfoKHR createInfo = { 0 }; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = vk->surface; @@ -1340,7 +1346,9 @@ 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; - createInfo.oldSwapchain = VK_NULL_HANDLE; // TODO + if (vk->swapchain->pNext) { + createInfo.oldSwapchain = vk->swapchain->pNext->rawSwapchain; + } VkResult result; if ((result = vk->dev->vkCreateSwapchainKHR(vk->device, &createInfo, ALLOC_VK, &vk->swapchain->rawSwapchain))) { rvkSetErrMsg(vk, "Could not create swapchain: %d", result); @@ -1349,11 +1357,10 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height) return 0; } -static void rvkDestroyRawSwapchain(struct RenderVulkan *vk) +static void rvkDestroyRawSwapchain(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain) { - if (vk->swapchain && vk->swapchain->rawSwapchain) { - vk->dev->vkDestroySwapchainKHR(vk->device, vk->swapchain->rawSwapchain, ALLOC_VK); - memset(&vk->swapchain, 0, sizeof(vk->swapchain)); + if (swapchain && swapchain->rawSwapchain) { + vk->dev->vkDestroySwapchainKHR(vk->device, swapchain->rawSwapchain, ALLOC_VK); } } @@ -1425,19 +1432,18 @@ static VkResult allocateCommandBuffers(struct RenderVulkan *vk) allocInfo.commandPool = vk->commandPool; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandBufferCount = vk->swapchain->nImages; - vk->commandBuffers = malloc(vk->swapchain->nImages * sizeof(vk->commandBuffers)); - return vk->dev->vkAllocateCommandBuffers(vk->device, &allocInfo, vk->commandBuffers); + vk->swapchain->commandBuffers = malloc(vk->swapchain->nImages * sizeof(vk->swapchain->commandBuffers)); + return vk->dev->vkAllocateCommandBuffers(vk->device, &allocInfo, vk->swapchain->commandBuffers); } -static void freeCommandBuffers(struct RenderVulkan *vk) +static void freeCommandBuffers(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain) { - if (vk->commandBuffers) { + if (swapchain && swapchain->commandBuffers) { vk->dev->vkFreeCommandBuffers(vk->device, vk->commandPool, - vk->swapchain->nImages, - vk->commandBuffers); - free(vk->commandBuffers); - vk->commandBuffers = NULL; + swapchain->nImages, + swapchain->commandBuffers); + free(swapchain->commandBuffers); } } @@ -1483,24 +1489,24 @@ static int recordCommandBuffers(struct RenderVulkan *vk) toPresentBarrier.image = vk->swapchain->images[i]; toPresentBarrier.subresourceRange = range; - vk->dev->vkBeginCommandBuffer(vk->commandBuffers[i], &beginInfo); - vk->dev->vkCmdPipelineBarrier(vk->commandBuffers[i], + vk->dev->vkBeginCommandBuffer(vk->swapchain->commandBuffers[i], &beginInfo); + vk->dev->vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &toClearBarrier); - vk->dev->vkCmdClearColorImage(vk->commandBuffers[i], vk->swapchain->images[i], + vk->dev->vkCmdClearColorImage(vk->swapchain->commandBuffers[i], vk->swapchain->images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue, 1, &range); - vk->dev->vkCmdPipelineBarrier(vk->commandBuffers[i], + vk->dev->vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &toPresentBarrier); - vk->dev->vkEndCommandBuffer(vk->commandBuffers[i]); + vk->dev->vkEndCommandBuffer(vk->swapchain->commandBuffers[i]); } return 0; @@ -1508,7 +1514,9 @@ static int recordCommandBuffers(struct RenderVulkan *vk) int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int height) { + struct SwapchainVulkan *oldSwapchain = vk->swapchain; vk->swapchain = calloc(1, sizeof(*vk->swapchain)); + vk->swapchain->pNext = oldSwapchain; if (rvkCreateRawSwapchain(vk, width, height)) { return -1; } @@ -1537,24 +1545,33 @@ int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int heigh return 0; } -void rvkDestroySwapchain(struct RenderVulkan *vk) +// TODO: Move device into RenderDev to limit scope +void rvkDestroySwapchain(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain) { - if (vk->swapchain && vk->swapchain->fences) { - for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { - if (vk->swapchain->fences[i]) { + if (swapchain && swapchain->fences) { + for (uint32_t i = 0; i < swapchain->nImages; ++i) { + if (swapchain->fences[i]) { vk->dev->vkDestroyFence(vk->device, - vk->swapchain->fences[i], + swapchain->fences[i], ALLOC_VK); } } - free(vk->swapchain->fences); - vk->swapchain->fences = NULL; - } - freeCommandBuffers(vk); - destroySwapchainImageViews(vk->device, vk->dev, vk->swapchain); - rvkDestroyRawSwapchain(vk); - free(vk->swapchain); - vk->swapchain = NULL; + free(swapchain->fences); + } + freeCommandBuffers(vk, swapchain); + destroySwapchainImageViews(vk->device, vk->dev, swapchain); + rvkDestroyRawSwapchain(vk, swapchain); + free(swapchain); +} + +// TODO: Destroy retired swapchains during rendering; not just all at once at destroy time. +void rvkDestroyAllSwapchains(struct RenderVulkan *vk) +{ + struct SwapchainVulkan *swapchain, *pNext; + for (swapchain = vk->swapchain; swapchain; swapchain = pNext) { + pNext = swapchain->pNext; + rvkDestroySwapchain(vk, swapchain); + } } /** Creates any semaphores or fences for this application. */ @@ -1584,7 +1601,8 @@ static void rvkCloseDevice(struct RenderVulkan *vk) if (vk->device) { if (vk->dev->vkDeviceWaitIdle) vk->dev->vkDeviceWaitIdle(vk->device); rvkDestroySyncObjects(vk); - rvkDestroySwapchain(vk); + //rvkDestroySwapchain(vk); + rvkDestroyAllSwapchains(vk); if (vk->commandPool) { vk->dev->vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); vk->commandPool = VK_NULL_HANDLE; @@ -1682,18 +1700,29 @@ PuglStatus onDisplay(PuglView *view) { struct RenderVulkan *vk = puglGetHandle(view); uint32_t imageIndex; + PuglRect frame; VkResult result; // TODO: Swapchain recreation when resizing, minimizing, etc. - if ((result = vk->dev->vkAcquireNextImageKHR( + while ((result = vk->dev->vkAcquireNextImageKHR( vk->device, vk->swapchain->rawSwapchain, UINT64_MAX, vk->sync.semaphore.presentComplete, VK_NULL_HANDLE, &imageIndex))) { - rvkSetErrMsg(vk, "Could not acquire swapchain image: %d", result); - return PUGL_FAILURE; + switch (result) { + case VK_SUCCESS: + break; + case VK_SUBOPTIMAL_KHR: + case VK_ERROR_OUT_OF_DATE_KHR: + frame = puglGetFrame(vk->view); + CHECK_RVK(vk, rvkCreateSwapchain(vk, frame.width, frame.height)); + continue; + default: + rvkSetErrMsg(vk, "Could not acquire swapchain image: %d", result); + rvkFatal(vk); + } } /* If running continuously and with an asynchronous presentation engine, @@ -1716,7 +1745,7 @@ PuglStatus onDisplay(PuglView *view) submitInfo.pWaitSemaphores = &vk->sync.semaphore.presentComplete; submitInfo.pWaitDstStageMask = &waitStage; submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vk->commandBuffers[imageIndex]; + submitInfo.pCommandBuffers = &vk->swapchain->commandBuffers[imageIndex]; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &vk->sync.semaphore.renderFinished; -- cgit v1.2.1