summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Halase <jordan@halase.me>2019-11-07 23:55:37 -0600
committerJordan Halase <jordan@halase.me>2019-11-07 23:55:37 -0600
commit9e3b1faeddacb78d342ae630815cb19030846a6f (patch)
tree68517eac36f98c2e4cfcc95b34f2441704fa5d9e
parent92ae03a9c8783bc224e8ffd1bb675d648c33b460 (diff)
Support manually collecting swapchain garbage
-rwxr-xr-xmain.c103
1 files 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;
}