From 2257c6155c75670c3135991bb73a89ece0853ce2 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Fri, 19 Apr 2024 13:16:00 +0200 Subject: [PATCH] wlbg: eliminate xev --- scripts/mzteriver/build.zig.zon | 4 +- scripts/vinput/build.zig.zon | 4 +- scripts/wlbg/build.zig | 4 - scripts/wlbg/build.zig.zon | 8 +- scripts/wlbg/src/DrawTimerHandler.zig | 49 +++--- scripts/wlbg/src/Gfx.zig | 6 +- scripts/wlbg/src/main.zig | 228 ++++++++++---------------- 7 files changed, 123 insertions(+), 180 deletions(-) diff --git a/scripts/mzteriver/build.zig.zon b/scripts/mzteriver/build.zig.zon index 7b7480d..1819da8 100644 --- a/scripts/mzteriver/build.zig.zon +++ b/scripts/mzteriver/build.zig.zon @@ -5,8 +5,8 @@ .dependencies = .{ .common = .{ .path = "../../lib/common-zig" }, .wayland = .{ - .url = "git+https://git.mzte.de/LordMZTE/zig-wayland#4f4ade382d582845b092de450527e3e7e0133f07", - .hash = "122087ee3bdff43049bf1d58513622c5f3c1430308665af0ee8961a22b60c4c10c1a", + .url = "git+https://git.mzte.de/LordMZTE/zig-wayland#1164c9eaa59442e6a8ec8e994fd5d30c23e4ed6d", + .hash = "122064a0e836c603b42720f101cd1b983f9b79f2457b58afdfa1aca1d7c406e80b83", }, }, diff --git a/scripts/vinput/build.zig.zon b/scripts/vinput/build.zig.zon index 06dbd37..49bd63a 100644 --- a/scripts/vinput/build.zig.zon +++ b/scripts/vinput/build.zig.zon @@ -5,8 +5,8 @@ .dependencies = .{ .common = .{ .path = "../../lib/common-zig" }, .wayland = .{ - .url = "git+https://git.mzte.de/LordMZTE/zig-wayland#4f4ade382d582845b092de450527e3e7e0133f07", - .hash = "122087ee3bdff43049bf1d58513622c5f3c1430308665af0ee8961a22b60c4c10c1a", + .url = "git+https://git.mzte.de/LordMZTE/zig-wayland#1164c9eaa59442e6a8ec8e994fd5d30c23e4ed6d", + .hash = "122064a0e836c603b42720f101cd1b983f9b79f2457b58afdfa1aca1d7c406e80b83", }, }, } diff --git a/scripts/wlbg/build.zig b/scripts/wlbg/build.zig index 7e52a37..c3fd93e 100644 --- a/scripts/wlbg/build.zig +++ b/scripts/wlbg/build.zig @@ -17,10 +17,6 @@ pub fn build(b: *std.Build) void { }); exe.root_module.addImport("common", b.dependency("common", .{}).module("common")); - exe.root_module.addImport("xev", b.dependency("xev", .{ - .target = target, - .optimize = optimize, - }).module("xev")); exe.root_module.addImport("wayland", wayland_mod); scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml"); diff --git a/scripts/wlbg/build.zig.zon b/scripts/wlbg/build.zig.zon index c3b295e..8dcc29b 100644 --- a/scripts/wlbg/build.zig.zon +++ b/scripts/wlbg/build.zig.zon @@ -5,12 +5,8 @@ .dependencies = .{ .common = .{ .path = "../../lib/common-zig" }, .wayland = .{ - .url = "git+https://git.mzte.de/LordMZTE/zig-wayland#4f4ade382d582845b092de450527e3e7e0133f07", - .hash = "122087ee3bdff43049bf1d58513622c5f3c1430308665af0ee8961a22b60c4c10c1a", - }, - .xev = .{ - .url = "git+https://github.com/mitchellh/libxev#0f73adfda1cff9c740160717b5431ebada6b8755", - .hash = "12203dcbe098ee49ea242432cd198b1ca557626988f056bea86630dcfe8660244407", + .url = "git+https://git.mzte.de/LordMZTE/zig-wayland#1164c9eaa59442e6a8ec8e994fd5d30c23e4ed6d", + .hash = "122064a0e836c603b42720f101cd1b983f9b79f2457b58afdfa1aca1d7c406e80b83", }, }, } diff --git a/scripts/wlbg/src/DrawTimerHandler.zig b/scripts/wlbg/src/DrawTimerHandler.zig index 794705b..ff57475 100644 --- a/scripts/wlbg/src/DrawTimerHandler.zig +++ b/scripts/wlbg/src/DrawTimerHandler.zig @@ -1,45 +1,46 @@ const std = @import("std"); -const xev = @import("xev"); const options = @import("options.zig"); -loop: *xev.Loop, - -/// Completion of the main redraw timer -completion: *xev.Completion, +timerfd: std.posix.fd_t, +timerfd_active: bool = false, /// Contains a bool for each output, true if needs redraw should_redraw: []bool, const DrawTimerHandler = @This(); -pub fn nextAction(self: *DrawTimerHandler) xev.CallbackAction { +pub const timerspec: std.os.linux.itimerspec = spec: { + const interval = 1000 / options.fps; + + break :spec .{ + .it_value = .{ .tv_sec = 0, .tv_nsec = 1 }, + .it_interval = .{ + .tv_sec = @divTrunc(interval, std.time.ms_per_s), + .tv_nsec = @mod(interval, std.time.ms_per_s) * std.time.ns_per_ms, + }, + }; +}; + +pub fn shouldDisarm(self: *DrawTimerHandler) bool { for (self.should_redraw) |ro| - if (ro) return .rearm; - return .disarm; + if (ro) return false; + return true; } -pub fn maybeWake(self: *DrawTimerHandler) void { - if (self.completion.flags.state == .dead and self.nextAction() == .rearm) { - self.resetTimer(); - self.loop.add(self.completion); +pub fn maybeWake(self: *DrawTimerHandler) !void { + if (!self.timerfd_active and !self.shouldDisarm()) { + try std.posix.timerfd_settime(self.timerfd, .{}, &timerspec, null); + self.timerfd_active = true; } } -pub fn resetTimer(self: *DrawTimerHandler) void { - const next_time = self.loop.now() + 1000 / options.fps; - self.completion.op.timer.reset = .{ - .tv_sec = @divTrunc(next_time, std.time.ms_per_s), - .tv_nsec = @mod(next_time, std.time.ms_per_s) * std.time.ns_per_ms, - }; -} - -pub fn damage(self: *DrawTimerHandler, idx: usize) void { +pub fn damage(self: *DrawTimerHandler, idx: usize) !void { self.should_redraw[idx] = true; - self.maybeWake(); + try self.maybeWake(); } -pub fn damageAll(self: *DrawTimerHandler) void { +pub fn damageAll(self: *DrawTimerHandler) !void { @memset(self.should_redraw, true); - self.maybeWake(); + try self.maybeWake(); } diff --git a/scripts/wlbg/src/Gfx.zig b/scripts/wlbg/src/Gfx.zig index b5b7a06..20b5775 100644 --- a/scripts/wlbg/src/Gfx.zig +++ b/scripts/wlbg/src/Gfx.zig @@ -194,7 +194,7 @@ pub fn preDraw( )); if (new_x != pos[0] or new_y != pos[1]) - dth.damage(i); + try dth.damage(i); pos[0] = new_x; pos[1] = new_y; @@ -278,8 +278,8 @@ pub fn draw( self.egl_dpy, outputs[output_idx].egl_surface, ) != c.EGL_TRUE) return error.EGLError; - if (self.dpy.dispatchPending() != .SUCCESS) return error.RoundtipFail; - std.debug.assert(self.dpy.prepareRead()); + while (!self.dpy.prepareRead()) + if (self.dpy.dispatchPending() != .SUCCESS) return error.RoundtipFail; } pub fn drawBackground( diff --git a/scripts/wlbg/src/main.zig b/scripts/wlbg/src/main.zig index 36cc349..3e72007 100644 --- a/scripts/wlbg/src/main.zig +++ b/scripts/wlbg/src/main.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const xev = @import("xev"); const wayland = @import("wayland"); const c = @import("ffi.zig").c; @@ -22,10 +21,6 @@ pub const std_options = std.Options{ }; pub fn main() !void { - std.log.info("initializing event loop", .{}); - var loop = try xev.Loop.init(.{}); - defer loop.deinit(); - std.log.info("connecting to wayland display", .{}); const dpy = try wl.Display.connect(null); defer dpy.disconnect(); @@ -136,14 +131,12 @@ pub fn main() !void { } defer for (output_windows) |output| output.deinit(egl_ctx); - var r_timer_completion: xev.Completion = undefined; - var r_timer = try xev.Timer.init(); - defer r_timer.deinit(); + const r_timerfd = try std.posix.timerfd_create(std.posix.CLOCK.MONOTONIC, .{}); + defer std.posix.close(r_timerfd); var dth = DrawTimerHandler{ .should_redraw = try std.heap.c_allocator.alloc(bool, output_info.len), - .completion = &r_timer_completion, - .loop = &loop, + .timerfd = r_timerfd, }; defer std.heap.c_allocator.free(dth.should_redraw); @memset(dth.should_redraw, true); @@ -206,46 +199,56 @@ pub fn main() !void { .egl_ctx = egl_ctx, .outputs = output_windows, .output_info = output_info, - .last_time = loop.now(), + .last_time = std.time.milliTimestamp(), .base_offset = base_offset, .pointer_state = &pointer_state, .dth = &dth, }; - var rbg_timer_completion: xev.Completion = undefined; - var rbg_timer = try xev.Timer.init(); - defer rbg_timer.deinit(); + const rbg_timerfd = try std.posix.timerfd_create(std.posix.CLOCK.MONOTONIC, .{}); + defer std.posix.close(rbg_timerfd); - rbg_timer.run( - &loop, - &rbg_timer_completion, - 0, - RenderData, - &rdata, - renderBackgroundCb, - ); - - r_timer.run( - &loop, - &r_timer_completion, - 0, - RenderData, - &rdata, - renderCb, - ); - - var wl_poll_completion = xev.Completion{ - .op = .{ .poll = .{ .fd = dpy.getFd() } }, - .userdata = dpy, - .callback = wlPollCb, - }; - loop.add(&wl_poll_completion); + try std.posix.timerfd_settime(r_timerfd, .{}, &DrawTimerHandler.timerspec, null); + try std.posix.timerfd_settime(rbg_timerfd, .{}, &.{ + .it_value = .{ .tv_sec = 0, .tv_nsec = 1 }, + .it_interval = .{ + .tv_sec = @divTrunc(options.refresh_time, std.time.ms_per_s), + .tv_nsec = @mod(options.refresh_time, std.time.ms_per_s) * std.time.ns_per_ms, + }, + }, null); if (dpy.dispatchPending() != .SUCCESS) return error.RoundtipFail; std.debug.assert(dpy.prepareRead()); + const epfd = try std.posix.epoll_create1(0); + defer std.posix.close(epfd); + + for ([_]std.posix.fd_t{ r_timerfd, rbg_timerfd, dpy.getFd() }) |fd| { + var ev = std.os.linux.epoll_event{ + .data = .{ .fd = fd }, + .events = std.os.linux.EPOLL.IN, + }; + + try std.posix.epoll_ctl(epfd, std.os.linux.EPOLL.CTL_ADD, fd, &ev); + } + std.log.info("running event loop", .{}); - try loop.run(.until_done); + var events: [32]std.os.linux.epoll_event = undefined; + while (true) { + const evs = events[0..std.posix.epoll_wait(epfd, &events, -1)]; + for (evs) |ev| { + var tfd_buf: [@sizeOf(usize)]u8 = undefined; + if (ev.data.fd == dpy.getFd()) { + try wlPoll(dpy); + } else if (ev.data.fd == r_timerfd) { + std.debug.assert(try std.posix.read(r_timerfd, &tfd_buf) == tfd_buf.len); + try render(&rdata); + } else if (ev.data.fd == rbg_timerfd) { + std.debug.assert(try std.posix.read(rbg_timerfd, &tfd_buf) == tfd_buf.len); + try renderBackground(&rdata); + } + } + } } const RenderData = struct { @@ -254,128 +257,83 @@ const RenderData = struct { egl_ctx: c.EGLContext, outputs: []const OutputWindow, output_info: []const OutputInfo, - last_time: isize, + last_time: i64, base_offset: [2]c_int, pointer_state: *PointerState, dth: *DrawTimerHandler, }; -fn renderCb( - data: ?*RenderData, - loop: *xev.Loop, - completion: *xev.Completion, - result: xev.Timer.RunError!void, -) xev.CallbackAction { - _ = completion; - result catch unreachable; +fn render(data: *RenderData) !void { + const now = std.time.milliTimestamp(); + const delta_time = now - data.last_time; + data.last_time = now; - const now = loop.now(); - const delta_time = now - data.?.last_time; - data.?.last_time = now; - - data.?.dth.resetTimer(); - - data.?.gfx.preDraw( + try data.gfx.preDraw( delta_time, - data.?.pointer_state, - data.?.output_info, - data.?.dth, - ) catch |e| { - std.log.err("running preDraw: {}", .{e}); - loop.stop(); - return .disarm; - }; + data.pointer_state, + data.output_info, + data.dth, + ); - for (data.?.outputs, 0..) |output, i| { - if (!data.?.dth.should_redraw[i]) + const should_disarm = data.dth.shouldDisarm(); + + for (data.outputs, 0..) |output, i| { + if (!data.dth.should_redraw[i]) continue; if (c.eglMakeCurrent( - data.?.egl_dpy, + data.egl_dpy, output.egl_surface, output.egl_surface, - data.?.egl_ctx, + data.egl_ctx, ) != c.EGL_TRUE) { std.log.err("failed to set EGL context", .{}); - loop.stop(); - return .disarm; + return error.EGLError; } - data.?.gfx.draw( + try data.gfx.draw( delta_time, - data.?.pointer_state, + data.pointer_state, i, - data.?.outputs, - data.?.output_info, - data.?.dth, - ) catch |e| { - std.log.err("drawing: {}", .{e}); - loop.stop(); - return .disarm; - }; + data.outputs, + data.output_info, + data.dth, + ); } - return data.?.dth.nextAction(); + if (data.dth.timerfd_active and should_disarm) { + try std.posix.timerfd_settime( + data.dth.timerfd, + .{}, + &std.mem.zeroInit(std.os.linux.itimerspec, .{}), + null, + ); + data.dth.timerfd_active = false; + } } -fn renderBackgroundCb( - data: ?*RenderData, - loop: *xev.Loop, - completion: *xev.Completion, - result: xev.Timer.RunError!void, -) xev.CallbackAction { - result catch unreachable; - - resetXevTimerCompletion(completion, loop.now(), options.refresh_time); - +fn renderBackground(data: *RenderData) !void { var rand: f32 = if (options.multihead_mode == .combined) std.crypto.random.float(f32) else 0.0; - for (data.?.output_info, 0..) |info, i| { + for (data.output_info, 0..) |info, i| { if (options.multihead_mode == .individual) rand = std.crypto.random.float(f32); - data.?.gfx.drawBackground( + try data.gfx.drawBackground( info, i, - data.?.base_offset, + data.base_offset, rand, - ) catch |e| { - std.log.err("drawing background: {}", .{e}); - loop.stop(); - return .disarm; - }; + ); } - data.?.dth.damageAll(); - - return .rearm; + try data.dth.damageAll(); } -fn wlPollCb( - userdata: ?*anyopaque, - loop: *xev.Loop, - _: *xev.Completion, - result: xev.Result, -) xev.CallbackAction { - result.poll catch |e| { - std.log.err("unable to poll wayland FD: {}", .{e}); - loop.stop(); - return .disarm; - }; +fn wlPoll(dpy: *wl.Display) !void { + if (dpy.readEvents() != .SUCCESS) + return error.DispatchFail; - const dpy: *wl.Display = @ptrCast(@alignCast(userdata)); - if (dpy.readEvents() != .SUCCESS) { - std.log.err("error reading wayland events", .{}); - loop.stop(); - return .disarm; - } - - while (!dpy.prepareRead()) { - if (dpy.dispatchPending() != .SUCCESS or dpy.flush() != .SUCCESS) { - std.log.err("error processing wayland events", .{}); - loop.stop(); - return .disarm; - } - } - - return .rearm; + while (!dpy.prepareRead()) + if (dpy.dispatchPending() != .SUCCESS or dpy.flush() != .SUCCESS) + return error.DispatchFail; } fn layerSurfaceListener(lsurf: *zwlr.LayerSurfaceV1, ev: zwlr.LayerSurfaceV1.Event, winsize: *?[2]c_int) void { @@ -417,13 +375,13 @@ fn pointerListener(_: *wl.Pointer, ev: wl.Pointer.Event, d: *PointerListenerData motion.surface_x.toInt(), motion.surface_y.toInt(), }; - d.dth.damage(i); + d.dth.damage(i) catch {}; } }, .enter => |enter| { for (d.outputs, 0..) |out, i| { if (out.surface == enter.surface) { - d.dth.damage(i); + d.dth.damage(i) catch {}; d.pstate.active_surface_idx = i; break; } @@ -431,7 +389,7 @@ fn pointerListener(_: *wl.Pointer, ev: wl.Pointer.Event, d: *PointerListenerData }, .leave => { if (d.pstate.active_surface_idx) |i| { - d.dth.damage(i); + d.dth.damage(i) catch {}; d.pstate.active_surface_idx = null; } }, @@ -439,14 +397,6 @@ fn pointerListener(_: *wl.Pointer, ev: wl.Pointer.Event, d: *PointerListenerData } } -fn resetXevTimerCompletion(completion: *xev.Completion, now: i64, in: i64) void { - const next_time = now + in; - completion.op.timer.reset = .{ - .tv_sec = @divTrunc(next_time, std.time.ms_per_s), - .tv_nsec = @mod(next_time, std.time.ms_per_s) * std.time.ns_per_ms, - }; -} - fn glDebugCb( source: c.GLenum, @"type": c.GLenum,