10cbcfdb
Handle out-of-date swapchains during draw
a73x 2026-04-08 15:33
diff --git a/src/main.zig b/src/main.zig index 4375d32..c347b40 100644 --- a/src/main.zig +++ b/src/main.zig @@ -310,11 +310,18 @@ fn runTerminal(alloc: std.mem.Allocator) !void { try ctx.uploadInstances(instances.items); } try ctx.drawCells( ctx.drawCells( @intCast(instances.items.len), .{ @floatFromInt(cell_w), @floatFromInt(cell_h) }, default_bg, ); ) catch |err| switch (err) { error.OutOfDateKHR => { _ = try ctx.vkd.deviceWaitIdle(ctx.device); try ctx.recreateSwapchain(window.width, window.height); continue; }, else => return err, }; } _ = try ctx.vkd.deviceWaitIdle(ctx.device); @@ -509,7 +516,14 @@ fn runDrawSmokeTest(alloc: std.mem.Allocator) !void { _ = conn.display.readEvents(); } _ = conn.display.dispatchPending(); try ctx.drawCells(1, .{ cell_w, cell_h }, .{ 0.0, 0.0, 0.0, 1.0 }); ctx.drawCells(1, .{ cell_w, cell_h }, .{ 0.0, 0.0, 0.0, 1.0 }) catch |err| switch (err) { error.OutOfDateKHR => { _ = try ctx.vkd.deviceWaitIdle(ctx.device); try ctx.recreateSwapchain(window.width, window.height); continue; }, else => return err, }; _ = conn.display.flush(); std.Thread.sleep(16 * std.time.ns_per_ms); } diff --git a/src/renderer.zig b/src/renderer.zig index 682b8be..21603db 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -313,6 +313,10 @@ fn nextInstanceCapacity(current: u32, needed: u32) u32 { return capacity; } fn swapchainNeedsRebuild(result: vk.Result) bool { return result == .suboptimal_khr; } pub const Context = struct { alloc: std.mem.Allocator, vkb: vk.BaseWrapper, @@ -998,13 +1002,17 @@ pub const Context = struct { try self.vkd.resetFences(self.device, 1, @ptrCast(&self.in_flight_fence)); // Acquire next image const acquire = try self.vkd.acquireNextImageKHR( const acquire = self.vkd.acquireNextImageKHR( self.device, self.swapchain, std.math.maxInt(u64), self.image_available, .null_handle, ); ) catch |err| switch (err) { error.OutOfDateKHR => return error.OutOfDateKHR, else => return err, }; if (swapchainNeedsRebuild(acquire.result)) return error.OutOfDateKHR; const image_index = acquire.image_index; // Record command buffer @@ -1046,13 +1054,17 @@ pub const Context = struct { }), self.in_flight_fence); // Present _ = try self.vkd.queuePresentKHR(self.present_queue, &vk.PresentInfoKHR{ const present_result = self.vkd.queuePresentKHR(self.present_queue, &vk.PresentInfoKHR{ .wait_semaphore_count = 1, .p_wait_semaphores = @ptrCast(&self.render_finished), .swapchain_count = 1, .p_swapchains = @ptrCast(&self.swapchain), .p_image_indices = @ptrCast(&image_index), }); }) catch |err| switch (err) { error.OutOfDateKHR => return error.OutOfDateKHR, else => return err, }; if (swapchainNeedsRebuild(present_result)) return error.OutOfDateKHR; } /// Upload CPU R8 pixels into the GPU atlas image. @@ -1193,13 +1205,17 @@ pub const Context = struct { try self.vkd.resetFences(self.device, 1, @ptrCast(&self.in_flight_fence)); // Acquire next image const acquire = try self.vkd.acquireNextImageKHR( const acquire = self.vkd.acquireNextImageKHR( self.device, self.swapchain, std.math.maxInt(u64), self.image_available, .null_handle, ); ) catch |err| switch (err) { error.OutOfDateKHR => return error.OutOfDateKHR, else => return err, }; if (swapchainNeedsRebuild(acquire.result)) return error.OutOfDateKHR; const image_index = acquire.image_index; // Record command buffer @@ -1289,13 +1305,17 @@ pub const Context = struct { }), self.in_flight_fence); // Present _ = try self.vkd.queuePresentKHR(self.present_queue, &vk.PresentInfoKHR{ const present_result = self.vkd.queuePresentKHR(self.present_queue, &vk.PresentInfoKHR{ .wait_semaphore_count = 1, .p_wait_semaphores = @ptrCast(&self.render_finished), .swapchain_count = 1, .p_swapchains = @ptrCast(&self.swapchain), .p_image_indices = @ptrCast(&image_index), }); }) catch |err| switch (err) { error.OutOfDateKHR => return error.OutOfDateKHR, else => return err, }; if (swapchainNeedsRebuild(present_result)) return error.OutOfDateKHR; } }; @@ -1320,3 +1340,8 @@ test "nextInstanceCapacity grows geometrically" { try std.testing.expectEqual(@as(u32, 32_000), nextInstanceCapacity(16_000, 16_001)); try std.testing.expectEqual(@as(u32, 4), nextInstanceCapacity(1, 3)); } test "swapchainNeedsRebuild flags suboptimal result" { try std.testing.expect(swapchainNeedsRebuild(.suboptimal_khr)); try std.testing.expect(!swapchainNeedsRebuild(.success)); }