a73x

33c334d6

Migrate runTextCoverageCompare to FrameLoop

a73x   2026-04-16 11:23

Commit message
Migrate runTextCoverageCompare to FrameLoop

Drops the manual 16ms sleep and prepareRead/cancelRead dance in favor
of the shared readiness primitive. Same visual output; now also
freeze-safe under workspace change.

src/main.zig
Old New
@@ -2555,26 +2555,22 @@ fn runTextCoverageCompare(alloc: std.mem.Allocator) !void {
2555 atlas.dirty = false; 2555 atlas.dirty = false;
2556 try ctx.uploadInstances(scene.instances.items); 2556 try ctx.uploadInstances(scene.instances.items);
2557 2557
2558 const wl_fd = conn.display.getFd(); 2558 var frame_loop = frame_loop_mod.FrameLoop.init(
2559 var pollfds = [_]std.posix.pollfd{ 2559 window.displayOps(conn.display),
2560 .{ .fd = wl_fd, .events = std.posix.POLL.IN, .revents = 0 }, 2560 window.surfaceStateView(),
2561 }; 2561 );
2562 defer frame_loop.deinit();
2563 window.frame_loop = &frame_loop;
2564 defer window.frame_loop = null;
2565
2562 var last_window_w = window.width; 2566 var last_window_w = window.width;
2563 var last_window_h = window.height; 2567 var last_window_h = window.height;
2564 var last_scale: i32 = geom.buffer_scale; 2568 var last_scale: i32 = geom.buffer_scale;
2565 2569
2566 while (!window.should_close) { 2570 while (!window.should_close) {
2567 _ = conn.display.flush(); 2571 try frame_loop.waitForWork(&.{}, 16);
2568 if (conn.display.prepareRead()) { 2572
2569 pollfds[0].revents = 0; 2573 if (!frame_loop.canRender()) continue;
2570 _ = std.posix.poll(&pollfds, 16) catch {};
2571 if (pollfds[0].revents & std.posix.POLL.IN != 0) {
2572 _ = conn.display.readEvents();
2573 } else {
2574 conn.display.cancelRead();
2575 }
2576 }
2577 _ = conn.display.dispatchPending();
2578 2574
2579 const current_scale = window.bufferScale(); 2575 const current_scale = window.bufferScale();
2580 const scale_changed = current_scale != last_scale; 2576 const scale_changed = current_scale != last_scale;
@@ -2592,15 +2588,8 @@ fn runTextCoverageCompare(alloc: std.mem.Allocator) !void {
2592 config.font_size_px, 2588 config.font_size_px,
2593 current_scale, 2589 current_scale,
2594 ); 2590 );
2595 // Rebuild the scene against the fresh atlas.
2596 scene.deinit(alloc); 2591 scene.deinit(alloc);
2597 scene = try buildTextCoverageCompareScene(alloc, &face, &atlas); 2592 scene = try buildTextCoverageCompareScene(alloc, &face, &atlas);
2598
2599 // Do NOT touch window.width/window.height here — those reflect the
2600 // compositor's configured surface size (from xdg_toplevel.configure).
2601 // Overwriting them forced sway to non-integer-scale our buffer to fit
2602 // its tile, which was the actual cause of the residual fuzz.
2603
2604 window.surface.setBufferScale(geom.buffer_scale); 2593 window.surface.setBufferScale(geom.buffer_scale);
2605 try ctx.uploadAtlas(atlas.pixels); 2594 try ctx.uploadAtlas(atlas.pixels);
2606 atlas.dirty = false; 2595 atlas.dirty = false;
@@ -2611,7 +2600,6 @@ fn runTextCoverageCompare(alloc: std.mem.Allocator) !void {
2611 const buf_w = window.width * @as(u32, @intCast(geom.buffer_scale)); 2600 const buf_w = window.width * @as(u32, @intCast(geom.buffer_scale));
2612 const buf_h = window.height * @as(u32, @intCast(geom.buffer_scale)); 2601 const buf_h = window.height * @as(u32, @intCast(geom.buffer_scale));
2613 try ctx.recreateSwapchain(buf_w, buf_h); 2602 try ctx.recreateSwapchain(buf_w, buf_h);
2614
2615 last_window_w = window.width; 2603 last_window_w = window.width;
2616 last_window_h = window.height; 2604 last_window_h = window.height;
2617 } 2605 }
@@ -2630,13 +2618,13 @@ fn runTextCoverageCompare(alloc: std.mem.Allocator) !void {
2630 try ctx.recreateSwapchain(buf_w, buf_h); 2618 try ctx.recreateSwapchain(buf_w, buf_h);
2631 last_window_w = window.width; 2619 last_window_w = window.width;
2632 last_window_h = window.height; 2620 last_window_h = window.height;
2621 frame_loop.forceArm();
2633 continue; 2622 continue;
2634 }, 2623 },
2635 else => return err, 2624 else => return err,
2636 }; 2625 };
2637 2626
2638 _ = conn.display.flush(); 2627 try frame_loop.commitRender();
2639 std.Thread.sleep(16 * std.time.ns_per_ms);
2640 } 2628 }
2641 2629
2642 _ = try ctx.vkd.deviceWaitIdle(ctx.device); 2630 _ = try ctx.vkd.deviceWaitIdle(ctx.device);