a73x

6be8f234

main: add exponential backoff on Vulkan timeout retries

a73x   2026-04-18 15:25

Commit message
main: add exponential backoff on Vulkan timeout retries

If the driver is genuinely wedged, the timeout-retry loop would spin
at full speed. Track consecutive VkWaitTimeout / VkAcquireTimeout
events and sleep 5ms * N (capped at 100ms) before retrying. Counter
resets on any successful frame.

Closes issue ab6c92f0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

src/main.zig
Old New
@@ -337,6 +337,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
337 var render_pending = true; 337 var render_pending = true;
338 var resize_pending = false; 338 var resize_pending = false;
339 var scale_pending = false; 339 var scale_pending = false;
340 var consecutive_vk_timeouts: u32 = 0;
340 341
341 while (!window.should_close and p.isChildAlive()) { 342 while (!window.should_close and p.isChildAlive()) {
342 const repeat_timeout_ms = remainingRepeatTimeoutMs(keyboard.nextRepeatDeadlineNs()); 343 const repeat_timeout_ms = remainingRepeatTimeoutMs(keyboard.nextRepeatDeadlineNs());
@@ -601,6 +602,9 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
601 ) catch |err| switch (err) { 602 ) catch |err| switch (err) {
602 error.VkWaitTimeout => { 603 error.VkWaitTimeout => {
603 vk_sync.logVkTimeout(@src(), .atlas); 604 vk_sync.logVkTimeout(@src(), .atlas);
605 consecutive_vk_timeouts +|= 1;
606 const backoff_us: u64 = @min(@as(u64, consecutive_vk_timeouts) * 5_000, 100_000);
607 std.Thread.sleep(backoff_us * std.time.ns_per_us);
604 render_pending = true; 608 render_pending = true;
605 continue; 609 continue;
606 }, 610 },
@@ -696,11 +700,15 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
696 }, 700 },
697 error.VkWaitTimeout, error.VkAcquireTimeout => { 701 error.VkWaitTimeout, error.VkAcquireTimeout => {
698 vk_sync.logVkTimeout(@src(), .fence); 702 vk_sync.logVkTimeout(@src(), .fence);
703 consecutive_vk_timeouts +|= 1;
704 const backoff_us: u64 = @min(@as(u64, consecutive_vk_timeouts) * 5_000, 100_000);
705 std.Thread.sleep(backoff_us * std.time.ns_per_us);
699 render_pending = true; 706 render_pending = true;
700 continue; 707 continue;
701 }, 708 },
702 else => return err, 709 else => return err,
703 }; 710 };
711 consecutive_vk_timeouts = 0;
704 frame_timing.gpu_submit_us = usFromTimer(&section_timer); 712 frame_timing.gpu_submit_us = usFromTimer(&section_timer);
705 frame_timing.wait_fences_us = submit_timing.wait_fences_us; 713 frame_timing.wait_fences_us = submit_timing.wait_fences_us;
706 frame_timing.acquire_us = submit_timing.acquire_us; 714 frame_timing.acquire_us = submit_timing.acquire_us;