Well window resizing works but we have a major memory leak

This commit is contained in:
Warwick 2025-01-16 17:55:52 +00:00
parent a6c3d2b0f2
commit 83eebb7674

View file

@ -41,6 +41,8 @@ const char *validationLayers[] = {"VK_LAYER_KHRONOS_validation"};
size_t validationLayerCount = size_t validationLayerCount =
sizeof(validationLayers) / sizeof(validationLayers[0]); sizeof(validationLayers) / sizeof(validationLayers[0]);
static bool framebufferResized; // initialised to 0
typedef struct Application { typedef struct Application {
GLFWwindow *window; GLFWwindow *window;
VkInstance instance; VkInstance instance;
@ -64,9 +66,9 @@ typedef struct Application {
uint32_t swapChainFramebufferCount; uint32_t swapChainFramebufferCount;
VkCommandPool commandPool; VkCommandPool commandPool;
VkCommandBuffer commandBuffers[MAX_FRAMES_IN_FLIGHT]; VkCommandBuffer commandBuffers[MAX_FRAMES_IN_FLIGHT];
VkSemaphore imageAvailableSemaphore[MAX_FRAMES_IN_FLIGHT]; VkSemaphore imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT];
VkSemaphore renderFinishedSemaphore[MAX_FRAMES_IN_FLIGHT]; VkSemaphore renderFinishedSemaphore[MAX_FRAMES_IN_FLIGHT];
VkFence inFlightFence[MAX_FRAMES_IN_FLIGHT]; VkFence inFlightFences[MAX_FRAMES_IN_FLIGHT];
uint32_t currentFrame; // initialised to 0 uint32_t currentFrame; // initialised to 0
} Application; } Application;
@ -204,11 +206,18 @@ void createInstance(Application *app) {
} }
} }
static void framebufferResizeCallback(GLFWwindow *window, int width,
int height) {
framebufferResized = true;
}
void initWindow(Application *app) { void initWindow(Application *app) {
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
app->window = glfwCreateWindow(800, 600, "Vulkan", NULL, NULL); app->window = glfwCreateWindow(800, 600, "Vulkan", NULL, NULL);
glfwSetFramebufferSizeCallback(app->window, framebufferResizeCallback);
} }
VkResult CreateDebugUtilsMessengerEXT( VkResult CreateDebugUtilsMessengerEXT(
@ -997,10 +1006,10 @@ void createSyncObjects(Application *app) {
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
if (vkCreateSemaphore(app->device, &semaphoreInfo, NULL, if (vkCreateSemaphore(app->device, &semaphoreInfo, NULL,
&app->imageAvailableSemaphore[i]) != VK_SUCCESS || &app->imageAvailableSemaphores[i]) != VK_SUCCESS ||
vkCreateSemaphore(app->device, &semaphoreInfo, NULL, vkCreateSemaphore(app->device, &semaphoreInfo, NULL,
&app->renderFinishedSemaphore[i]) != VK_SUCCESS || &app->renderFinishedSemaphore[i]) != VK_SUCCESS ||
vkCreateFence(app->device, &fenceInfo, NULL, &app->inFlightFence[i]) != vkCreateFence(app->device, &fenceInfo, NULL, &app->inFlightFences[i]) !=
VK_SUCCESS) { VK_SUCCESS) {
fprintf(stderr, "Failed to create semaphores!"); fprintf(stderr, "Failed to create semaphores!");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -1008,6 +1017,37 @@ void createSyncObjects(Application *app) {
} }
} }
void cleanupSwapChain(Application *app) {
for (size_t i = 0; i < app->swapChainFramebufferCount; i++) {
vkDestroyFramebuffer(app->device, app->swapChainFramebuffers[i], NULL);
}
for (size_t i = 0; i < app->swapChainImageViewCount; i++) {
vkDestroyImageView(app->device, app->swapChainImageViews[i], NULL);
}
vkDestroySwapchainKHR(app->device, app->swapChain, NULL);
}
void recreateSwapChain(Application *app) {
int width = 0, height = 0;
glfwGetFramebufferSize(app->window, &width, &height);
while (width == 0 || height == 0) {
glfwGetFramebufferSize(app->window, &width, &height);
glfwWaitEvents();
}
vkDeviceWaitIdle(app->device);
free(app->swapChainFramebuffers);
free(app->swapChainImageViews);
free(app->swapChainImages);
createSwapChain(app);
createImageViews(app);
createFramebuffers(app);
}
void initVulkan(Application *app) { void initVulkan(Application *app) {
createInstance(app); createInstance(app);
setupDebugMessenger(app); setupDebugMessenger(app);
@ -1025,20 +1065,33 @@ void initVulkan(Application *app) {
} }
void drawFrame(Application *app) { void drawFrame(Application *app) {
vkWaitForFences(app->device, 1, &app->inFlightFence[app->currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(app->device, 1, &app->inFlightFences[app->currentFrame],
vkResetFences(app->device, 1, &app->inFlightFence[app->currentFrame]); VK_TRUE, UINT64_MAX);
uint32_t imageIndex; uint32_t imageIndex;
VkResult result =
vkAcquireNextImageKHR(app->device, app->swapChain, UINT64_MAX, vkAcquireNextImageKHR(app->device, app->swapChain, UINT64_MAX,
app->imageAvailableSemaphore[app->currentFrame], VK_NULL_HANDLE, app->imageAvailableSemaphores[app->currentFrame],
&imageIndex); VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapChain(app);
return;
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
fprintf(stderr, "Failed to acquire swap chain image!");
exit(EXIT_FAILURE);
}
// Only reset the fence if we are submitting work
vkResetFences(app->device, 1, &app->inFlightFences[app->currentFrame]);
vkResetCommandBuffer(app->commandBuffers[app->currentFrame], 0); vkResetCommandBuffer(app->commandBuffers[app->currentFrame], 0);
recordCommandBuffer(app, app->commandBuffers[app->currentFrame], imageIndex); recordCommandBuffer(app, app->commandBuffers[app->currentFrame], imageIndex);
VkSubmitInfo submitInfo = {0}; VkSubmitInfo submitInfo = {0};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {app->imageAvailableSemaphore[app->currentFrame]}; VkSemaphore waitSemaphores[] = {
app->imageAvailableSemaphores[app->currentFrame]};
VkPipelineStageFlags waitStages[] = { VkPipelineStageFlags waitStages[] = {
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;
@ -1046,12 +1099,13 @@ void drawFrame(Application *app) {
submitInfo.pWaitDstStageMask = waitStages; submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &app->commandBuffers[app->currentFrame]; submitInfo.pCommandBuffers = &app->commandBuffers[app->currentFrame];
VkSemaphore signalSemaphores[] = {app->renderFinishedSemaphore[app->currentFrame]}; VkSemaphore signalSemaphores[] = {
app->renderFinishedSemaphore[app->currentFrame]};
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores; submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(app->graphicsQueue, 1, &submitInfo, app->inFlightFence[app->currentFrame]) != if (vkQueueSubmit(app->graphicsQueue, 1, &submitInfo,
VK_SUCCESS) { app->inFlightFences[app->currentFrame]) != VK_SUCCESS) {
fprintf(stderr, "failed to submit draw command buffer!"); fprintf(stderr, "failed to submit draw command buffer!");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -1066,7 +1120,15 @@ void drawFrame(Application *app) {
presentInfo.pImageIndices = &imageIndex; presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = NULL; // Optional presentInfo.pResults = NULL; // Optional
vkQueuePresentKHR(app->presentQueue, &presentInfo); result = vkQueuePresentKHR(app->presentQueue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR ||
framebufferResized) {
framebufferResized = false;
recreateSwapChain(app);
} else if (result != VK_SUCCESS) {
fprintf(stderr, "failed to present swap chain image!");
exit(EXIT_FAILURE);
}
app->currentFrame = (app->currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; app->currentFrame = (app->currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
} }
@ -1081,25 +1143,23 @@ void mainLoop(Application *app) {
} }
void cleanup(Application *app) { void cleanup(Application *app) {
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { cleanupSwapChain(app);
vkDestroySemaphore(app->device, app->imageAvailableSemaphore[i], NULL);
vkDestroySemaphore(app->device, app->renderFinishedSemaphore[i], NULL);
vkDestroyFence(app->device, app->inFlightFence[i], NULL);
}
vkDestroyCommandPool(app->device, app->commandPool, NULL);
for (uint i = 0; i < app->swapChainFramebufferCount; i++) {
vkDestroyFramebuffer(app->device, app->swapChainFramebuffers[i], NULL);
}
free(app->swapChainFramebuffers); free(app->swapChainFramebuffers);
vkDestroyPipeline(app->device, app->graphicsPipeline, NULL);
vkDestroyPipelineLayout(app->device, app->pipelineLayout, NULL);
vkDestroyRenderPass(app->device, app->renderPass, NULL);
for (size_t i = 0; i < app->swapChainImageViewCount; i++) {
vkDestroyImageView(app->device, app->swapChainImageViews[i], NULL);
}
free(app->swapChainImageViews); free(app->swapChainImageViews);
free(app->swapChainImages); free(app->swapChainImages);
vkDestroySwapchainKHR(app->device, app->swapChain, NULL);
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroySemaphore(app->device, app->imageAvailableSemaphores[i], NULL);
vkDestroySemaphore(app->device, app->renderFinishedSemaphore[i], NULL);
vkDestroyFence(app->device, app->inFlightFences[i], NULL);
}
vkDestroyCommandPool(app->device, app->commandPool, NULL);
vkDestroyPipeline(app->device, app->graphicsPipeline, NULL);
vkDestroyPipelineLayout(app->device, app->pipelineLayout, NULL);
vkDestroyRenderPass(app->device, app->renderPass, NULL);
vkDestroyDevice(app->device, NULL); vkDestroyDevice(app->device, NULL);
if (enableValidationLayers) { if (enableValidationLayers) {
DestroyDebugUtilsMessengerEXT(app->instance, app->debugMessenger, NULL); DestroyDebugUtilsMessengerEXT(app->instance, app->debugMessenger, NULL);