Smooth rendering!

This commit is contained in:
2026-05-05 22:45:41 +02:00
parent 10365c135b
commit 10cbf61e52
+107 -96
View File
@@ -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);