wlbg: only do one frame per minute

F gpu
This commit is contained in:
LordMZTE 2023-10-27 15:30:28 +02:00
parent 1e04919f26
commit 7c64072005
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
4 changed files with 125 additions and 31 deletions

View file

@ -16,6 +16,10 @@ pub fn build(b: *std.Build) void {
.optimize = optimize, .optimize = optimize,
}); });
exe.addModule("xev", b.dependency("xev", .{
.target = target,
.optimize = optimize,
}).module("xev"));
exe.addModule("wayland", wayland_mod); exe.addModule("wayland", wayland_mod);
scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml"); scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml");

View file

@ -7,5 +7,9 @@
.url = "https://git.mzte.de/LordMZTE/zig-wayland/archive/85722422985f928087e56d90c3617ecb04232486.tar.gz", .url = "https://git.mzte.de/LordMZTE/zig-wayland/archive/85722422985f928087e56d90c3617ecb04232486.tar.gz",
.hash = "1220d992b223e473988d203d66d262e54141b59559c09587eb00231c800d46f9b408", .hash = "1220d992b223e473988d203d66d262e54141b59559c09587eb00231c800d46f9b408",
}, },
.xev = .{
.url = "https://github.com/mitchellh/libxev/archive/5ecbc871f3bfa80fb7bf0fa853866cb93b99bc18.tar.gz",
.hash = "1220416854e424601ecc9814afb461a5dc9cf95db5917d82f794594a58ffc723b82c",
},
}, },
} }

View file

@ -7,7 +7,6 @@ const OutputInfo = @import("OutputInfo.zig");
egl_dpy: c.EGLDisplay, egl_dpy: c.EGLDisplay,
bg_shader_program: c_uint, bg_shader_program: c_uint,
time: f64,
const Gfx = @This(); const Gfx = @This();
@ -31,7 +30,6 @@ pub fn init(egl_dpy: c.EGLDisplay) !Gfx {
return .{ return .{
.egl_dpy = egl_dpy, .egl_dpy = egl_dpy,
.bg_shader_program = program, .bg_shader_program = program,
.time = 0.0,
}; };
} }
@ -40,15 +38,15 @@ pub fn deinit(self: *Gfx) void {
self.* = undefined; self.* = undefined;
} }
pub fn draw( pub fn drawBackground(
self: *Gfx, self: *Gfx,
dt: f32, dt: i64,
egl_surface: c.EGLSurface, egl_surface: c.EGLSurface,
info: OutputInfo, info: OutputInfo,
base_xoff: i32, base_xoff: i32,
base_yoff: i32, base_yoff: i32,
) !void { ) !void {
self.time += dt; _ = dt;
// There's just about a 0% chance this works properly when monitors have different resolutions, // There's just about a 0% chance this works properly when monitors have different resolutions,
// but I can't even begin thinking about that. // but I can't even begin thinking about that.
@ -76,9 +74,11 @@ pub fn draw(
c.glVertexAttribPointer(1, 2, c.GL_FLOAT, c.GL_FALSE, @sizeOf(f32) * 5, @ptrFromInt(@intFromPtr(&vertices) + @sizeOf(f32) * 3)); c.glVertexAttribPointer(1, 2, c.GL_FLOAT, c.GL_FALSE, @sizeOf(f32) * 5, @ptrFromInt(@intFromPtr(&vertices) + @sizeOf(f32) * 3));
c.glEnableVertexAttribArray(1); c.glEnableVertexAttribArray(1);
c.glUniform1f(c.glGetUniformLocation(self.bg_shader_program, "time"), @as(f32, @floatCast(self.time / 10000.0))); const rand = std.crypto.random.float(f32);
c.glUniform1f(c.glGetUniformLocation(self.bg_shader_program, "time"), rand * 2000.0 - 1000.0);
c.glDrawArrays(c.GL_TRIANGLES, 0, vertices.len / 3); c.glDrawArrays(c.GL_TRIANGLES, 0, vertices.len / 3);
if (c.eglSwapBuffers(self.egl_dpy, egl_surface) != c.EGL_TRUE) return error.EGLError; if (c.eglSwapInterval(self.egl_dpy, 0) != c.EGL_TRUE or
c.eglSwapBuffers(self.egl_dpy, egl_surface) != c.EGL_TRUE) return error.EGLError;
} }

View file

@ -12,9 +12,11 @@ const wl = wayland.client.wl;
const zwlr = wayland.client.zwlr; const zwlr = wayland.client.zwlr;
const zxdg = wayland.client.zxdg; const zxdg = wayland.client.zxdg;
const fps = 10;
pub fn main() !void { 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", .{}); std.log.info("connecting to wayland display", .{});
const dpy = try wl.Display.connect(null); const dpy = try wl.Display.connect(null);
defer dpy.disconnect(); defer dpy.disconnect();
@ -146,32 +148,116 @@ pub fn main() !void {
var gfx = try Gfx.init(egl_dpy); var gfx = try Gfx.init(egl_dpy);
defer gfx.deinit(); defer gfx.deinit();
var timer = try std.time.Timer.start(); var rbgdata = RenderBackgroundData{
var prev_time = std.time.milliTimestamp(); .gfx = &gfx,
while (true) { .egl_dpy = egl_dpy,
const now_time = std.time.milliTimestamp(); .egl_ctx = egl_ctx,
const delta_time: f32 = @floatFromInt(now_time - prev_time); .outputs = output_windows,
prev_time = now_time; .output_info = output_info,
.last_time = loop.now(),
.base_offset = .{ base_xoff, base_yoff },
};
for (output_windows, output_info) |output, info| { var rbg_timer_completion: xev.Completion = undefined;
if (c.eglMakeCurrent( var rbg_timer = try xev.Timer.init();
egl_dpy, defer rbg_timer.deinit();
output.egl_surface,
output.egl_surface, rbg_timer.run(
egl_ctx, &loop,
) != c.EGL_TRUE) return error.EGLError; &rbg_timer_completion,
try gfx.draw(delta_time, output.egl_surface, info, base_xoff, base_yoff); 0,
RenderBackgroundData,
&rbgdata,
renderBackgroundCb,
);
var wl_poll_completion = xev.Completion{
.op = .{ .poll = .{ .fd = dpy.getFd() } },
.userdata = dpy,
.callback = wlPollCb,
};
loop.add(&wl_poll_completion);
std.log.info("running event loop", .{});
try loop.run(.until_done);
}
const RenderBackgroundData = struct {
gfx: *Gfx,
egl_dpy: c.EGLDisplay,
egl_ctx: c.EGLContext,
outputs: []const OutputWindow,
output_info: []const OutputInfo,
last_time: isize,
base_offset: [2]c_int,
};
fn renderBackgroundCb(
data: ?*RenderBackgroundData,
loop: *xev.Loop,
completion: *xev.Completion,
result: xev.Timer.RunError!void,
) xev.CallbackAction {
result catch unreachable;
const now = loop.now();
const delta_time = now - data.?.last_time;
data.?.last_time = now;
const next_time = now + std.time.ms_per_min;
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,
};
for (data.?.outputs, data.?.output_info) |output, info| {
if (c.eglMakeCurrent(
data.?.egl_dpy,
output.egl_surface,
output.egl_surface,
data.?.egl_ctx,
) != c.EGL_TRUE) {
std.log.err("failed to set EGL context", .{});
loop.stop();
return .disarm;
} }
if (dpy.dispatchPending() != .SUCCESS or dpy.flush() != .SUCCESS) { data.?.gfx.drawBackground(
std.log.err("error processing wayland events", .{}); delta_time,
return error.DispatchFail; output.egl_surface,
} info,
data.?.base_offset[0],
const elapsed = timer.lap(); data.?.base_offset[1],
if (elapsed < 1000 * std.time.ns_per_ms / fps) ) catch |e| {
std.os.nanosleep(0, (1000 * std.time.ns_per_ms) / fps - elapsed); std.log.err("drawing: {}", .{e});
loop.stop();
return .disarm;
};
} }
return .rearm;
}
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;
};
const dpy: *wl.Display = @ptrCast(@alignCast(userdata));
if (dpy.dispatchPending() != .SUCCESS or dpy.flush() != .SUCCESS) {
std.log.err("error processing wayland events", .{});
loop.stop();
return .disarm;
}
return .rearm;
} }
const OutputWindow = struct { const OutputWindow = struct {