From 10cbf61e520d429f29e683713fff7aff4c6f395f Mon Sep 17 00:00:00 2001 From: Simen Kirkvik Date: Tue, 5 May 2026 22:45:41 +0200 Subject: [PATCH] Smooth rendering! --- src/main.zig | 203 +++++++++++++++++++++++++++------------------------ 1 file changed, 107 insertions(+), 96 deletions(-) diff --git a/src/main.zig b/src/main.zig index 7f8ac19..805ee6a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -51,10 +51,14 @@ const WaylandState = struct { surface: ?*c.wl_surface, buffer: ?*c.wl_buffer, + shared_memory_pool_data: []u8, + xkb_context: ?*c.xkb_context, xkb_keymap: ?*c.xkb_keymap, xkb_state: ?*c.xkb_state, + io: std.Io, + clock: std.Io.Clock, allocator: std.mem.Allocator, resize: bool, @@ -66,6 +70,7 @@ const WaylandState = struct { pointer_event: WlPointerEvent, + app_memory: puzzle.platform.AppMemory, app_input: puzzle.platform.AppInput, }; @@ -124,6 +129,42 @@ fn wlFrameHandleDone(data: ?*anyopaque, callback: ?*c.wl_callback, callback_data std.debug.print("[Wayland] Frame ready\n", .{}); + const render_start_time = wl_state.clock.now(wl_state.io); + + wl_state.app_input.delta_time = 1.0 / 30.0; + + const app_offscreen_buffer: puzzle.platform.OffscreenBuffer = .{ + .width = wl_state.window_width, + .height = wl_state.window_height, + .stride = wl_state.window_width * 4, + .data = wl_state.shared_memory_pool_data, + }; + // wl_state.app_input.controls = puzzle.platform.Controls{ .key = old_key }; + puzzle.updateAndRender(wl_state.io, &wl_state.app_memory, app_offscreen_buffer, &wl_state.app_input); + + const render_end_time = wl_state.clock.now(wl_state.io); + const render_time = render_start_time.durationTo(render_end_time); + + std.debug.print("[Wayland] Render: {f}.\n", .{render_time}); + + // if (render_time.toNanoseconds() < frame_target_time_ns.toNanoseconds()) { + // const sleep_duration: std.Io.Clock.Duration = .{ + // .raw = .{ .nanoseconds = frame_target_time.nanoseconds - render_time.nanoseconds }, + // .clock = clock, + // }; + // std.debug.print("[Wayland] Sleeping: {f}.\n", .{sleep_duration.raw}); + // sleep_duration.sleep(io) catch { + // std.debug.print("[Wayland] Error sleeping\n", .{}); + // return 1; + // }; + // } else { + // std.debug.print("[Wayland] MISSED FRAME\n", .{}); + // } + + c.wl_surface_attach(wl_state.surface, wl_state.buffer, 0, 0); + c.wl_surface_damage_buffer(wl_state.surface, 0, 0, wl_state.window_width, wl_state.window_height); + c.wl_surface_commit(wl_state.surface); + wl_state.frame_commited = true; } @@ -146,12 +187,14 @@ fn xdg_surface_handle_configure(data: ?*anyopaque, xdg_surface: ?*c.xdg_surface, var wl_state: *WaylandState = @ptrCast(@alignCast(data)); c.xdg_surface_ack_configure(xdg_surface, serial); + c.wl_surface_commit(wl_state.surface); // TODO: Ready to resize? if (wl_state.window_resized) { wl_state.resize = true; } + std.debug.print("[Wayland] Configured.\n", .{}); wl_state.configured = true; } @@ -856,13 +899,19 @@ fn pollEvents(wl_state: *WaylandState, fds: *[1]linux.pollfd) void { pub fn main(init: std.process.Init) u8 { const io = init.io; + const clock = std.Io.Clock.awake; + const clock_resolution = clock.resolution(io) catch { + std.debug.print("[Wayland] ERROR: awake clock resoultion not supported.\n", .{}); + return 1; + }; + const display = c.wl_display_connect(null); if (display == null) { std.debug.print("Error connecting to wayland display.\n", .{}); return 1; } - const wl_fd = c.wl_display_get_fd(display); + // const wl_fd = c.wl_display_get_fd(display); std.debug.print("[Wayland] Connection established.\n", .{}); @@ -871,6 +920,8 @@ pub fn main(init: std.process.Init) u8 { wl_state.xkb_context = null; wl_state.xkb_state = null; wl_state.xkb_keymap = null; + wl_state.io = io; + wl_state.clock = clock; const registry = c.wl_display_get_registry(display); if (registry == null) { @@ -927,11 +978,6 @@ pub fn main(init: std.process.Init) u8 { wl_state.window_width = 1280; wl_state.window_height = 960; - const clock = std.Io.Clock.awake; - const clock_resolution = clock.resolution(io) catch { - std.debug.print("[Wayland] ERROR: awake clock resoultion not supported.\n", .{}); - return 1; - }; { var buf: [34]u8 = undefined; var w: std.Io.Writer = .fixed(&buf); @@ -943,11 +989,10 @@ pub fn main(init: std.process.Init) u8 { } var shared_memory_pool: ?*c.wl_shm_pool = undefined; - var shared_memory_pool_data: []u8 = undefined; - const monitor_update_hz: f64 = 30; - const game_update_hz: f64 = monitor_update_hz; - const frame_target_time_s: f64 = 1.0 / game_update_hz; + // const monitor_update_hz: f64 = 30; + // const game_update_hz: f64 = monitor_update_hz; + // const frame_target_time_s: f64 = 1.0 / game_update_hz; // const frame_target_time_ms: f64 = std.time.ms_per_s * frame_target_time_s; // const frame_target_time_ns = std.Io.Duration.fromNanoseconds(std.time.ns_per_ms * @as(u64, @intFromFloat(frame_target_time_ms))); // const frame_target_time = std.Io.Duration.fromNanoseconds(@intFromFloat(std.time.ns_per_s * frame_target_time_s)); @@ -963,7 +1008,7 @@ pub fn main(init: std.process.Init) u8 { return 1; }; - var app_memory: puzzle.platform.AppMemory = .{ + wl_state.app_memory = .{ .initialized = false, .permanent_storage = app_permanent_storage, }; @@ -974,98 +1019,64 @@ pub fn main(init: std.process.Init) u8 { std.debug.print("[Wayland] Added frame callback with ret {d}.\n", .{ret}); } + if (wl_state.resize) { + const new_pool = createSharedMemoryPool(wl_state) catch { + std.debug.print("[Wayland] Error creating memory pool!\n", .{}); + wl_state.running = false; + return 1; + }; + + std.debug.print( + "[Wayland] Reizing window to {d}x{d} = {d}B.\n", + .{ wl_state.window_width, wl_state.window_height, new_pool.data.len }, + ); + + shared_memory_pool = new_pool.pool; + wl_state.shared_memory_pool_data = new_pool.data; + + const stride = wl_state.window_width * 4; + const buffer = c.wl_shm_pool_create_buffer( + shared_memory_pool, + 0, + wl_state.window_width, + wl_state.window_height, + stride, + c.WL_SHM_FORMAT_ARGB8888, + ); + if (buffer) |buf| { + wl_state.buffer = buf; + } else { + std.debug.print("[Wayland] Error creating buffer!\n", .{}); + wl_state.running = false; + return 1; + } + + wl_state.resize = false; + wl_state.window_resized = false; + wl_state.frame_commited = true; + c.wl_surface_attach(wl_state.surface, wl_state.buffer, 0, 0); + c.wl_surface_damage_buffer(wl_state.surface, 0, 0, wl_state.window_width, wl_state.window_height); + c.wl_surface_commit(wl_state.surface); + } + var start = clock.now(io); var frame_count: u32 = 0; - var fds: [1]linux.pollfd = .{ - .{ - .fd = wl_fd, - .events = std.posix.POLL.IN, - .revents = 0, - }, - }; + // var fds: [1]linux.pollfd = .{ + // .{ + // .fd = wl_fd, + // .events = std.posix.POLL.IN, + // .revents = 0, + // }, + // }; while (wl_state.running) { - pollEvents(&wl_state, &fds); - - if (wl_state.resize) { - const new_pool = createSharedMemoryPool(wl_state) catch { - std.debug.print("[Wayland] Error creating memory pool!\n", .{}); - wl_state.running = false; - break; - }; - - std.debug.print( - "[Wayland] Reizing window to {d}x{d} = {d}B.\n", - .{ wl_state.window_width, wl_state.window_height, new_pool.data.len }, - ); - - shared_memory_pool = new_pool.pool; - shared_memory_pool_data = new_pool.data; - - const stride = wl_state.window_width * 4; - const buffer = c.wl_shm_pool_create_buffer( - shared_memory_pool, - 0, - wl_state.window_width, - wl_state.window_height, - stride, - c.WL_SHM_FORMAT_ARGB8888, - ); - if (buffer) |buf| { - wl_state.buffer = buf; - } else { - std.debug.print("[Wayland] Error creating buffer!\n", .{}); - wl_state.running = false; - break; - } - - wl_state.resize = false; - wl_state.window_resized = false; - wl_state.frame_commited = true; - c.wl_surface_attach(wl_state.surface, wl_state.buffer, 0, 0); - c.wl_surface_damage_buffer(wl_state.surface, 0, 0, wl_state.window_width, wl_state.window_height); - c.wl_surface_commit(wl_state.surface); + const ret = c.wl_display_dispatch(wl_state.display); + if (ret == -1) { + std.debug.print("[Wayland] Dispatch failed: exiting.\n", .{}); + wl_state.running = false; } - const render_start_time = clock.now(io); - - wl_state.app_input.delta_time = frame_target_time_s; - - const app_offscreen_buffer: puzzle.platform.OffscreenBuffer = .{ - .width = wl_state.window_width, - .height = wl_state.window_height, - .stride = wl_state.window_width * 4, - .data = shared_memory_pool_data, - }; - // wl_state.app_input.controls = puzzle.platform.Controls{ .key = old_key }; - puzzle.updateAndRender(io, &app_memory, app_offscreen_buffer, &wl_state.app_input); - - const render_end_time = clock.now(io); - const render_time = render_start_time.durationTo(render_end_time); - - std.debug.print("[Wayland] Render: {f}.\n", .{render_time}); - - // if (render_time.toNanoseconds() < frame_target_time_ns.toNanoseconds()) { - // const sleep_duration: std.Io.Clock.Duration = .{ - // .raw = .{ .nanoseconds = frame_target_time.nanoseconds - render_time.nanoseconds }, - // .clock = clock, - // }; - // std.debug.print("[Wayland] Sleeping: {f}.\n", .{sleep_duration.raw}); - // sleep_duration.sleep(io) catch { - // std.debug.print("[Wayland] Error sleeping\n", .{}); - // return 1; - // }; - // } else { - // std.debug.print("[Wayland] MISSED FRAME\n", .{}); - // } - - c.wl_surface_attach(wl_state.surface, wl_state.buffer, 0, 0); - c.wl_surface_damage_buffer(wl_state.surface, 0, 0, wl_state.window_width, wl_state.window_height); - c.wl_surface_commit(wl_state.surface); - - _ = c.wl_display_roundtrip(wl_state.display); - wl_state.frame_commited = false; const last = clock.now(io);