a73x

6be8f234

main: add exponential backoff on Vulkan timeout retries

a73x   2026-04-18 15:25

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>

diff --git a/src/main.zig b/src/main.zig
index 06d7af1..ec3e25f 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -337,6 +337,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
    var render_pending = true;
    var resize_pending = false;
    var scale_pending = false;
    var consecutive_vk_timeouts: u32 = 0;

    while (!window.should_close and p.isChildAlive()) {
        const repeat_timeout_ms = remainingRepeatTimeoutMs(keyboard.nextRepeatDeadlineNs());
@@ -601,6 +602,9 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
                ) catch |err| switch (err) {
                    error.VkWaitTimeout => {
                        vk_sync.logVkTimeout(@src(), .atlas);
                        consecutive_vk_timeouts +|= 1;
                        const backoff_us: u64 = @min(@as(u64, consecutive_vk_timeouts) * 5_000, 100_000);
                        std.Thread.sleep(backoff_us * std.time.ns_per_us);
                        render_pending = true;
                        continue;
                    },
@@ -696,11 +700,15 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
            },
            error.VkWaitTimeout, error.VkAcquireTimeout => {
                vk_sync.logVkTimeout(@src(), .fence);
                consecutive_vk_timeouts +|= 1;
                const backoff_us: u64 = @min(@as(u64, consecutive_vk_timeouts) * 5_000, 100_000);
                std.Thread.sleep(backoff_us * std.time.ns_per_us);
                render_pending = true;
                continue;
            },
            else => return err,
        };
        consecutive_vk_timeouts = 0;
        frame_timing.gpu_submit_us = usFromTimer(&section_timer);
        frame_timing.wait_fences_us = submit_timing.wait_fences_us;
        frame_timing.acquire_us = submit_timing.acquire_us;