Commit: dda0049f9455f32e0b48d72c7bc9baa1e84918b3
Parent: 9011f7a3136ffa3d72c60471c500c459a7f2a65f
Author: Randy Palamar
Date: Thu, 21 Aug 2025 19:49:36 -0600
core: support window resizing
Diffstat:
M | common.c | | | 59 | +++++++++++++++++++++++++++++++++++++++-------------------- |
M | util.h | | | 1 | + |
M | vulkan.h | | | 14 | +++++++++++++- |
3 files changed, 53 insertions(+), 21 deletions(-)
diff --git a/common.c b/common.c
@@ -55,6 +55,14 @@ key_callback(GLFWwindow *window, s32 key, s32 scancode, s32 action, s32 modifier
ctx->should_exit = 1;
}
+function void
+fb_callback(GLFWwindow *w, s32 width, s32 height)
+{
+ ViewerContext *v = glfwGetWindowUserPointer(w);
+ v->vulkan.swap_chain.framebuffer_resize = 1;
+ v->window_size = (sv2){{width, height}};
+}
+
function u32
vulkan_shader_kind_to_glslang_shader_kind(u32 kind)
{
@@ -511,6 +519,19 @@ find_best_graphics_device(VulkanContext *vctx, Arena arena)
return result;
}
+function VkExtent2D
+swap_chain_extent_for_window(GLFWwindow *w, VkSurfaceCapabilitiesKHR *si)
+{
+ VkExtent2D result = si->currentExtent;
+ if (result.width == U32_MAX)
+ glfwGetFramebufferSize(w, (s32 *)&result.width, (s32 *)&result.height);
+
+ result.width = CLAMP(result.width, si->minImageExtent.width, si->maxImageExtent.width);
+ result.height = CLAMP(result.height, si->minImageExtent.height, si->maxImageExtent.height);
+
+ return result;
+}
+
function void
swap_chain_from_existing(VulkanSwapChain *sc, VkDevice device, VkRenderPass render_pass, VkExtent2D extent,
VkSurfaceTransformFlagBitsKHR transform, u32 requested_images, Arena *arena)
@@ -545,7 +566,9 @@ swap_chain_from_existing(VulkanSwapChain *sc, VkDevice device, VkRenderPass rend
VkSwapchainKHR swap_chain;
/* TODO(rnp): custom allocator? */
vkCreateSwapchainKHR(device, &create_info, 0, &swap_chain);
- /* TODO(rnp): does the old one have to be destroyed here? */
+
+ vkDeviceWaitIdle(device);
+ vkDestroySwapchainKHR(device, sc->swap_chain, 0);
sc->swap_chain = swap_chain;
u32 image_count;
@@ -615,7 +638,6 @@ init_viewer(ViewerContext *ctx)
if (!glfwInit()) os_fatal(str8("failed to start glfw\n"));
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
ctx->window = glfwCreateWindow(ctx->window_size.w, ctx->window_size.h, "Camera CNN", 0, 0);
if (!ctx->window) os_fatal(str8("failed to open window\n"));
@@ -740,20 +762,7 @@ init_viewer(ViewerContext *ctx)
vkCreateRenderPass(v->device, &render_pass_info, 0, &rp->render.render_pass);
- VkExtent2D extent = surface_info.capabilities.currentExtent;
- if (extent.width == U32_MAX) {
- s32 width, height;
- glfwGetFramebufferSize(ctx->window, &width, &height);
- extent.width = (u32)width;
- extent.height = (u32)height;
- }
-
- extent.width = CLAMP(extent.width,
- surface_info.capabilities.minImageExtent.width,
- surface_info.capabilities.maxImageExtent.width);
- extent.height = CLAMP(extent.height,
- surface_info.capabilities.minImageExtent.height,
- surface_info.capabilities.maxImageExtent.height);
+ VkExtent2D extent = swap_chain_extent_for_window(ctx->window, &surface_info.capabilities);
sc->queue_index = 0;
sc->exclusive_queue = 1;
@@ -839,10 +848,10 @@ init_viewer(ViewerContext *ctx)
glfwSetWindowUserPointer(ctx->window, ctx);
glfwSetKeyCallback(ctx->window, key_callback);
+ glfwSetFramebufferSizeCallback(ctx->window, fb_callback);
#if 0
glfwSetScrollCallback(ctx->window, scroll_callback);
- glfwSetFramebufferSizeCallback(ctx->window, fb_callback);
#endif
}
@@ -897,7 +906,7 @@ begin_frame(VulkanContext *v)
}
function void
-end_frame(VulkanContext *v)
+end_frame(VulkanContext *v, GLFWwindow *window, Arena arena)
{
VulkanSwapChain *sc = &v->swap_chain;
VulkanPipeline *rp = &v->render_pipeline;
@@ -927,7 +936,17 @@ end_frame(VulkanContext *v)
vkCmdEndRenderPass(rp->render.command_buffers[index]);
vkEndCommandBuffer(rp->render.command_buffers[index]);
vkQueueSubmit(v->queue, 1, &submit_info, rp->render.command_buffer_fences[index]);
- vkQueuePresentKHR(v->queue, &present_info);
+ VkResult pres = vkQueuePresentKHR(v->queue, &present_info);
+ if (pres == VK_ERROR_OUT_OF_DATE_KHR || pres == VK_SUBOPTIMAL_KHR || sc->framebuffer_resize) {
+ sc->framebuffer_resize = 0;
+ struct VulkanSurfaceInfo surface_info;
+ fill_vulkan_surface_info(v->physical_device, sc->surface, &surface_info, &arena);
+ /* TODO(rnp): handle surface format change */
+
+ VkExtent2D extent = swap_chain_extent_for_window(window, &surface_info.capabilities);
+ swap_chain_from_existing(&v->swap_chain, v->device, rp->render.render_pass, extent,
+ surface_info.capabilities.currentTransform, sc->image_count, &arena);
+ }
sc->current_frame_index = (sc->current_frame_index + 1) % MAX_RENDER_FRAMES_IN_FLIGHT;
}
@@ -941,5 +960,5 @@ viewer_frame_step(ViewerContext *ctx, f32 dt)
VulkanPipeline *rp = &ctx->vulkan.render_pipeline;
begin_frame(&ctx->vulkan);
vkCmdDraw(rp->render.command_buffers[ctx->vulkan.swap_chain.current_frame_index], 3, 1, 0, 0);
- end_frame(&ctx->vulkan);
+ end_frame(&ctx->vulkan, ctx->window, ctx->arena);
}
diff --git a/util.h b/util.h
@@ -254,6 +254,7 @@ typedef struct {
u32 image_count;
u32 framebuffer_index;
u32 current_frame_index;
+ b32 framebuffer_resize;
} VulkanSwapChain;
typedef enum {
diff --git a/vulkan.h b/vulkan.h
@@ -18,7 +18,6 @@
typedef uint32_t VkBool32;
typedef uint32_t VkFlags;
-typedef uint32_t VkResult;
typedef uint32_t VkSampleMask;
typedef uint64_t VkDeviceSize;
typedef void * VkCommandBuffer;
@@ -42,6 +41,13 @@ typedef void * VkSurfaceKHR;
typedef void * VkSwapchainKHR;
typedef enum {
+ VK_SUCCESS = 0,
+ VK_SUBOPTIMAL_KHR = 1000001003,
+ VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
+ VK_RESULT_MAX_ENUM = 0x7FFFFFFF
+} VkResult;
+
+typedef enum {
VK_STRUCTURE_TYPE_APPLICATION_INFO = 0,
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,
@@ -1969,11 +1975,17 @@ VkResult vkQueueSubmit(VkQueue queue,
const VkSubmitInfo *pSubmits,
VkFence fence);
+VkResult vkDeviceWaitIdle(VkDevice device);
+
VkResult vkCreateSwapchainKHR(VkDevice device,
const VkSwapchainCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkSwapchainKHR *pSwapchain);
+void vkDestroySwapchainKHR(VkDevice device,
+ VkSwapchainKHR swapchain,
+ const VkAllocationCallbacks *pAllocator);
+
VkResult vkGetSwapchainImagesKHR(VkDevice device,
VkSwapchainKHR swapchain,
uint32_t *pSwapchainImageCount,