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,
});
exe.addModule("xev", b.dependency("xev", .{
.target = target,
.optimize = optimize,
}).module("xev"));
exe.addModule("wayland", wayland_mod);
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",
.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,
bg_shader_program: c_uint,
time: f64,
const Gfx = @This();
@ -31,7 +30,6 @@ pub fn init(egl_dpy: c.EGLDisplay) !Gfx {
return .{
.egl_dpy = egl_dpy,
.bg_shader_program = program,
.time = 0.0,
};
}
@ -40,15 +38,15 @@ pub fn deinit(self: *Gfx) void {
self.* = undefined;
}
pub fn draw(
pub fn drawBackground(
self: *Gfx,
dt: f32,
dt: i64,
egl_surface: c.EGLSurface,
info: OutputInfo,
base_xoff: i32,
base_yoff: i32,
) !void {
self.time += dt;
_ = dt;
// There's just about a 0% chance this works properly when monitors have different resolutions,
// 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.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);
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 zxdg = wayland.client.zxdg;
const fps = 10;
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();
@ -146,32 +148,116 @@ pub fn main() !void {
var gfx = try Gfx.init(egl_dpy);
defer gfx.deinit();
var timer = try std.time.Timer.start();
var prev_time = std.time.milliTimestamp();
while (true) {
const now_time = std.time.milliTimestamp();
const delta_time: f32 = @floatFromInt(now_time - prev_time);
prev_time = now_time;
var rbgdata = RenderBackgroundData{
.gfx = &gfx,
.egl_dpy = egl_dpy,
.egl_ctx = egl_ctx,
.outputs = output_windows,
.output_info = output_info,
.last_time = loop.now(),
.base_offset = .{ base_xoff, base_yoff },
};
for (output_windows, output_info) |output, info| {
if (c.eglMakeCurrent(
egl_dpy,
output.egl_surface,
output.egl_surface,
egl_ctx,
) != c.EGL_TRUE) return error.EGLError;
try gfx.draw(delta_time, output.egl_surface, info, base_xoff, base_yoff);
var rbg_timer_completion: xev.Completion = undefined;
var rbg_timer = try xev.Timer.init();
defer rbg_timer.deinit();
rbg_timer.run(
&loop,
&rbg_timer_completion,
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) {
std.log.err("error processing wayland events", .{});
return error.DispatchFail;
}
const elapsed = timer.lap();
if (elapsed < 1000 * std.time.ns_per_ms / fps)
std.os.nanosleep(0, (1000 * std.time.ns_per_ms) / fps - elapsed);
data.?.gfx.drawBackground(
delta_time,
output.egl_surface,
info,
data.?.base_offset[0],
data.?.base_offset[1],
) catch |e| {
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 {