diff options
| -rw-r--r-- | demos/cube.c | 136 | ||||
| -rw-r--r-- | demos/tri.c | 123 |
2 files changed, 228 insertions, 31 deletions
diff --git a/demos/cube.c b/demos/cube.c index b9193cb2..8acd7afa 100644 --- a/demos/cube.c +++ b/demos/cube.c @@ -347,7 +347,7 @@ struct demo { PFN_vkQueuePresentKHR fpQueuePresentKHR; VkSurfaceDescriptionWindowKHR surface_description; uint32_t swapchainImageCount; - VkSwapchainKHR swap_chain; + VkSwapchainKHR swapchain; SwapchainBuffers *buffers; VkCmdPool cmd_pool; @@ -407,6 +407,9 @@ struct demo { uint32_t queue_count; }; +// Forward declaration: +static void demo_resize(struct demo *demo); + static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) { // Search memtypes to find first index with those properties @@ -636,13 +639,23 @@ static void demo_draw(struct demo *demo) assert(!err); // Get the index of the next available swapchain image: - err = demo->fpAcquireNextImageKHR(demo->device, demo->swap_chain, + err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX, presentCompleteSemaphore, &demo->current_buffer); - // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR - // return codes - assert(!err); + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + // demo->swapchain is out of date (e.g. the window was resized) and + // must be recreated: + demo_resize(demo); + demo_draw(demo); + vkDestroySemaphore(demo->device, presentCompleteSemaphore); + return; + } else if (err == VK_SUBOPTIMAL_KHR) { + // demo->swapchain is not as optimal as it could be, but the platform's + // presentation engine will still present the image correctly. + } else { + assert(!err); + } // Assume the command buffer has been run on current_buffer before so // we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL @@ -674,15 +687,22 @@ static void demo_draw(struct demo *demo) .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = NULL, .swapchainCount = 1, - .swapchains = &demo->swap_chain, + .swapchains = &demo->swapchain, .imageIndices = &demo->current_buffer, }; // TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER? err = demo->fpQueuePresentKHR(demo->queue, &present); - // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR - // return codes - assert(!err); + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + // demo->swapchain is out of date (e.g. the window was resized) and + // must be recreated: + demo_resize(demo); + } else if (err == VK_SUBOPTIMAL_KHR) { + // demo->swapchain is not as optimal as it could be, but the platform's + // presentation engine will still present the image correctly. + } else { + assert(!err); + } err = vkQueueWaitIdle(demo->queue); assert(err == VK_SUCCESS); @@ -693,6 +713,7 @@ static void demo_draw(struct demo *demo) static void demo_prepare_buffers(struct demo *demo) { VkResult U_ASSERT_ONLY err; + VkSwapchainKHR oldSwapchain = demo->swapchain; // Check the surface properties and formats VkSurfacePropertiesKHR surfProperties; @@ -727,6 +748,8 @@ static void demo_prepare_buffers(struct demo *demo) { // If the surface size is defined, the swap chain size must match swapchainExtent = surfProperties.currentExtent; + demo->width = surfProperties.currentExtent.width; + demo->height = surfProperties.currentExtent.height; } // If mailbox mode is available, use it, as is the lowest-latency non- @@ -763,7 +786,7 @@ static void demo_prepare_buffers(struct demo *demo) preTransform = surfProperties.currentTransform; } - const VkSwapchainCreateInfoKHR swap_chain = { + const VkSwapchainCreateInfoKHR swapchain = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = NULL, .pSurfaceDescription = (const VkSurfaceDescriptionKHR *)&demo->surface_description, @@ -781,22 +804,30 @@ static void demo_prepare_buffers(struct demo *demo) .queueFamilyCount = 0, .pQueueFamilyIndices = NULL, .presentMode = swapchainPresentMode, - .oldSwapchain.handle = 0, + .oldSwapchain = oldSwapchain, .clipped = true, }; uint32_t i; - err = demo->fpCreateSwapchainKHR(demo->device, &swap_chain, &demo->swap_chain); + err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, &demo->swapchain); assert(!err); - err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain, + // If we just re-created an existing swapchain, we should destroy the old + // swapchain at this point. + // Note: destroying the swapchain also cleans up all its associated + // presentable images once the platform is done with them. + if (oldSwapchain.handle != VK_NULL_HANDLE) { + demo->fpDestroySwapchainKHR(demo->device, oldSwapchain); + } + + err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, &demo->swapchainImageCount, NULL); assert(!err); VkImage* swapchainImages = (VkImage*)malloc(demo->swapchainImageCount * sizeof(VkImage)); assert(swapchainImages); - err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain, + err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, &demo->swapchainImageCount, swapchainImages); assert(!err); @@ -1732,6 +1763,8 @@ static void demo_prepare(struct demo *demo) .count = 1, }; + demo->swapchain.handle = VK_NULL_HANDLE; + demo_prepare_buffers(demo); demo_prepare_depth(demo); demo_prepare_textures(demo); @@ -1790,7 +1823,7 @@ static void demo_cleanup(struct demo *demo) vkFreeMemory(demo->device, demo->textures[i].mem); vkDestroySampler(demo->device, demo->textures[i].sampler); } - demo->fpDestroySwapchainKHR(demo->device, demo->swap_chain); + demo->fpDestroySwapchainKHR(demo->device, demo->swapchain); vkDestroyImageView(demo->device, demo->depth.view); vkDestroyImage(demo->device, demo->depth.image); @@ -1821,6 +1854,67 @@ static void demo_cleanup(struct demo *demo) #endif // _WIN32 } +static void demo_resize(struct demo *demo) +{ + uint32_t i; + + // In order to properly resize the window, we must re-create the swapchain + // AND redo the command buffers, etc. + // + // First, perform part of the demo_cleanup() function: + demo->prepared = false; + + for (i = 0; i < demo->swapchainImageCount; i++) { + vkDestroyFramebuffer(demo->device, demo->framebuffers[i]); + } + free(demo->framebuffers); + vkDestroyDescriptorPool(demo->device, demo->desc_pool); + + vkDestroyPipeline(demo->device, demo->pipeline); + vkDestroyPipelineCache(demo->device, demo->pipelineCache); + vkDestroyRenderPass(demo->device, demo->render_pass); + vkDestroyPipelineLayout(demo->device, demo->pipeline_layout); + vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout); + + for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { + vkDestroyImageView(demo->device, demo->textures[i].view); + vkDestroyImage(demo->device, demo->textures[i].image); + vkFreeMemory(demo->device, demo->textures[i].mem); + vkDestroySampler(demo->device, demo->textures[i].sampler); + } +#if 0 + demo->fpDestroySwapchainKHR(demo->device, demo->swapchain); +#endif + + vkDestroyImageView(demo->device, demo->depth.view); + vkDestroyImage(demo->device, demo->depth.image); + vkFreeMemory(demo->device, demo->depth.mem); + + vkDestroyBuffer(demo->device, demo->uniform_data.buf); + vkFreeMemory(demo->device, demo->uniform_data.mem); + + for (i = 0; i < demo->swapchainImageCount; i++) { + vkDestroyImageView(demo->device, demo->buffers[i].view); + vkDestroyCommandBuffer(demo->device, demo->buffers[i].cmd); + } + free(demo->buffers); + +#if 0 + free(demo->queue_props); + + vkDestroyCommandPool(demo->device, demo->cmd_pool); + vkDestroyDevice(demo->device); + if (demo->validate) { + demo->dbgDestroyMsgCallback(demo->inst, demo->msg_callback); + } +#endif + + + // Second, re-perform the demo_prepare() function, which will re-create the + // swapchain: + demo_prepare(demo); +} + // On MS-Windows, make this a global, so it's available to WndProc() struct demo demo; @@ -1952,6 +2046,15 @@ static void demo_handle_event(struct demo *demo, } } break; + case XCB_CONFIGURE_NOTIFY: + { + const xcb_configure_notify_event_t *cfg = + (const xcb_configure_notify_event_t *) event; + if ((demo->width != cfg->width) || (demo->height != cfg->height)) { + demo_resize(demo); + } + } + break; default: break; } @@ -1998,7 +2101,8 @@ static void demo_create_window(struct demo *demo) value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; value_list[0] = demo->screen->black_pixel; value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | - XCB_EVENT_MASK_EXPOSURE; + XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY; xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, diff --git a/demos/tri.c b/demos/tri.c index 87205ea6..fa995490 100644 --- a/demos/tri.c +++ b/demos/tri.c @@ -192,7 +192,7 @@ struct demo { PFN_vkQueuePresentKHR fpQueuePresentKHR; VkSurfaceDescriptionWindowKHR surface_description; uint32_t swapchainImageCount; - VkSwapchainKHR swap_chain; + VkSwapchainKHR swapchain; SwapchainBuffers *buffers; VkCmdPool cmd_pool; @@ -247,6 +247,9 @@ struct demo { uint32_t queue_count; }; +// Forward declaration: +static void demo_resize(struct demo *demo); + static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) { // Search memtypes to find first index with those properties @@ -453,13 +456,23 @@ static void demo_draw(struct demo *demo) assert(!err); // Get the index of the next available swapchain image: - err = demo->fpAcquireNextImageKHR(demo->device, demo->swap_chain, + err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX, presentCompleteSemaphore, &demo->current_buffer); - // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR - // return codes - assert(!err); + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + // demo->swapchain is out of date (e.g. the window was resized) and + // must be recreated: + demo_resize(demo); + demo_draw(demo); + vkDestroySemaphore(demo->device, presentCompleteSemaphore); + return; + } else if (err == VK_SUBOPTIMAL_KHR) { + // demo->swapchain is not as optimal as it could be, but the platform's + // presentation engine will still present the image correctly. + } else { + assert(!err); + } // Assume the command buffer has been run on current_buffer before so // we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL @@ -494,15 +507,22 @@ static void demo_draw(struct demo *demo) .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = NULL, .swapchainCount = 1, - .swapchains = &demo->swap_chain, + .swapchains = &demo->swapchain, .imageIndices = &demo->current_buffer, }; // TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER? err = demo->fpQueuePresentKHR(demo->queue, &present); - // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR - // return codes - assert(!err); + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + // demo->swapchain is out of date (e.g. the window was resized) and + // must be recreated: + demo_resize(demo); + } else if (err == VK_SUBOPTIMAL_KHR) { + // demo->swapchain is not as optimal as it could be, but the platform's + // presentation engine will still present the image correctly. + } else { + assert(!err); + } err = vkQueueWaitIdle(demo->queue); assert(err == VK_SUCCESS); @@ -513,6 +533,7 @@ static void demo_draw(struct demo *demo) static void demo_prepare_buffers(struct demo *demo) { VkResult U_ASSERT_ONLY err; + VkSwapchainKHR oldSwapchain = demo->swapchain; // Check the surface proprties and formats VkSurfacePropertiesKHR surfProperties; @@ -547,6 +568,8 @@ static void demo_prepare_buffers(struct demo *demo) { // If the surface size is defined, the swap chain size must match swapchainExtent = surfProperties.currentExtent; + demo->width = surfProperties.currentExtent.width; + demo->height = surfProperties.currentExtent.height; } VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; @@ -569,7 +592,7 @@ static void demo_prepare_buffers(struct demo *demo) preTransform = surfProperties.currentTransform; } - const VkSwapchainCreateInfoKHR swap_chain = { + const VkSwapchainCreateInfoKHR swapchain = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = NULL, .pSurfaceDescription = (const VkSurfaceDescriptionKHR *)&demo->surface_description, @@ -587,22 +610,30 @@ static void demo_prepare_buffers(struct demo *demo) .queueFamilyCount = 0, .pQueueFamilyIndices = NULL, .presentMode = swapchainPresentMode, - .oldSwapchain.handle = 0, + .oldSwapchain = oldSwapchain, .clipped = true, }; uint32_t i; - err = demo->fpCreateSwapchainKHR(demo->device, &swap_chain, &demo->swap_chain); + err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, &demo->swapchain); assert(!err); - err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain, + // If we just re-created an existing swapchain, we should destroy the old + // swapchain at this point. + // Note: destroying the swapchain also cleans up all its associated + // presentable images once the platform is done with them. + if (oldSwapchain.handle != VK_NULL_HANDLE) { + demo->fpDestroySwapchainKHR(demo->device, oldSwapchain); + } + + err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, &demo->swapchainImageCount, NULL); assert(!err); VkImage* swapchainImages = (VkImage*)malloc(demo->swapchainImageCount * sizeof(VkImage)); assert(swapchainImages); - err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain, + err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, &demo->swapchainImageCount, swapchainImages); assert(!err); @@ -1482,6 +1513,8 @@ static void demo_prepare(struct demo *demo) err = vkAllocCommandBuffers(demo->device, &cmd, &demo->draw_cmd); assert(!err); + demo->swapchain.handle = VK_NULL_HANDLE; + demo_prepare_buffers(demo); demo_prepare_depth(demo); demo_prepare_textures(demo); @@ -1616,6 +1649,15 @@ static void demo_handle_event(struct demo *demo, case XCB_DESTROY_NOTIFY: demo->quit = true; break; + case XCB_CONFIGURE_NOTIFY: + { + const xcb_configure_notify_event_t *cfg = + (const xcb_configure_notify_event_t *) event; + if ((demo->width != cfg->width) || (demo->height != cfg->height)) { + demo_resize(demo); + } + } + break; default: break; } @@ -2193,7 +2235,7 @@ static void demo_cleanup(struct demo *demo) vkDestroyImage(demo->device, demo->depth.image); vkFreeMemory(demo->device, demo->depth.mem); - demo->fpDestroySwapchainKHR(demo->device, demo->swap_chain); + demo->fpDestroySwapchainKHR(demo->device, demo->swapchain); free(demo->buffers); vkDestroyDevice(demo->device); @@ -2208,6 +2250,57 @@ static void demo_cleanup(struct demo *demo) #endif // _WIN32 } +static void demo_resize(struct demo *demo) +{ + uint32_t i; + + // In order to properly resize the window, we must re-create the swapchain + // AND redo the command buffers, etc. + // + // First, perform part of the demo_cleanup() function: + demo->prepared = false; + + for (i = 0; i < demo->swapchainImageCount; i++) { + vkDestroyFramebuffer(demo->device, demo->framebuffers[i]); + } + free(demo->framebuffers); + vkDestroyDescriptorPool(demo->device, demo->desc_pool); + + if (demo->setup_cmd) { + vkDestroyCommandBuffer(demo->device, demo->setup_cmd); + demo->setup_cmd = 0; // Must clear this value + } + vkDestroyCommandBuffer(demo->device, demo->draw_cmd); + vkDestroyCommandPool(demo->device, demo->cmd_pool); + + vkDestroyPipeline(demo->device, demo->pipeline); + vkDestroyRenderPass(demo->device, demo->render_pass); + vkDestroyPipelineLayout(demo->device, demo->pipeline_layout); + vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout); + + vkDestroyBuffer(demo->device, demo->vertices.buf); + vkFreeMemory(demo->device, demo->vertices.mem); + + for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { + vkDestroyImageView(demo->device, demo->textures[i].view); + vkDestroyImage(demo->device, demo->textures[i].image); + vkFreeMemory(demo->device, demo->textures[i].mem); + vkDestroySampler(demo->device, demo->textures[i].sampler); + } + + for (i = 0; i < demo->swapchainImageCount; i++) { + vkDestroyImageView(demo->device, demo->buffers[i].view); + } + + vkDestroyImageView(demo->device, demo->depth.view); + vkDestroyImage(demo->device, demo->depth.image); + vkFreeMemory(demo->device, demo->depth.mem); + + // Second, re-perform the demo_prepare() function, which will re-create the + // swapchain: + demo_prepare(demo); +} + #ifdef _WIN32 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, |
