aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2026-04-13 10:54:29 +0000
committers-ol <s+removethis@s-ol.nu>2026-04-14 18:10:05 +0000
commit0c0154b352c66d57ced9f4fd648106919c007572 (patch)
treec057008b52011eeb7e4344b5611d51f8d0f7c0a0 /src
parentfix some memory leaks (diff)
downloadglsl-view-0c0154b352c66d57ced9f4fd648106919c007572.tar.gz
glsl-view-0c0154b352c66d57ced9f4fd648106919c007572.zip
configure outputs from CLI, move stdout into 'pipe' outputHEADmain
Diffstat (limited to 'src')
-rw-r--r--src/config.zig27
-rw-r--r--src/main.zig56
-rw-r--r--src/output.zig67
-rw-r--r--src/tsv.zig34
4 files changed, 128 insertions, 56 deletions
diff --git a/src/config.zig b/src/config.zig
index f1410d4..795c564 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -5,6 +5,7 @@ const build_config = @import("build_config");
pub const OutputConfig = union(enum) {
window: out.WindowOutput.Config,
+ stdout: out.StdoutOutput.Config,
texture_share_vk: if (build_config.have_tsv) @import("tsv.zig").TSVOutput.Config else void,
const default: OutputConfig = .{ .window = .default };
@@ -41,6 +42,8 @@ pub const Config = struct {
_ = it.skip();
+ var outputs = std.ArrayList(OutputConfig).empty;
+
while (it.next()) |arg| {
if (std.mem.eql(u8, arg, "--width")) {
config.width = try parseInt(&it, i32);
@@ -48,23 +51,27 @@ pub const Config = struct {
config.height = try parseInt(&it, i32);
} else if (std.mem.eql(u8, arg, "--osc")) {
config.osc = try parseString(&it, allocator);
+ } else if (std.mem.eql(u8, arg, "--window")) {
+ var window: OutputConfig = .{ .window = .default };
+ window.window.width = config.width;
+ window.window.height = config.height;
+ try outputs.append(allocator, window);
+ } else if (std.mem.eql(u8, arg, "--stdout")) {
+ try outputs.append(allocator, .{ .stdout = .default });
} else {
return error.invalidArgument;
}
- // @TODO: output config
}
- if (config.outputs.len == 0) {
- const num = 1;
- const outputs = try allocator.alloc(OutputConfig, num);
- for (0..num) |i| {
- outputs[i] = .{ .window = .default };
- outputs[i].window.width = config.width;
- outputs[i].window.height = config.height;
- }
- config.outputs = outputs;
+ if (outputs.items.len == 0) {
+ var window: OutputConfig = .{ .window = .default };
+ window.window.width = config.width;
+ window.window.height = config.height;
+ try outputs.append(allocator, window);
}
+ config.outputs = try outputs.toOwnedSlice(allocator);
+
return config;
}
};
diff --git a/src/main.zig b/src/main.zig
index 9b09945..0bf4cfc 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -120,14 +120,6 @@ pub fn main() !void {
var loops: u8 = 0;
- const stdout = std.fs.File.stdout();
- var tex_buffer: ?[]u8 = null;
-
- if (!stdout.isTty()) {
- tex_buffer = try allocator.alloc(u8, @intCast(config.width * config.height * 4));
- }
- defer if (tex_buffer) |buf| allocator.free(buf);
-
while (c.glfwWindowShouldClose(window) == c.GL_FALSE) {
c.glfwMakeContextCurrent(window);
@@ -145,24 +137,20 @@ pub fn main() !void {
// control.reload_requested = false;
// }
- if (control.dirty) {
+ const is_fresh = if (control.dirty) blk: {
c.glFinish();
var timer = try std.time.Timer.start();
- fbo.bind();
- c.glClear(c.GL_COLOR_BUFFER_BIT);
+ {
+ fbo.bind();
+ defer fbo.unbind();
- main_program.bind();
- constants.normalized_quad.draw();
+ c.glClear(c.GL_COLOR_BUFFER_BIT);
- if (tex_buffer) |buf| {
- fbo.read(config.width, config.height, buf);
- std.debug.print("writing {} bytes\n", .{buf.len});
- _ = try stdout.write(buf);
+ main_program.bind();
+ constants.normalized_quad.draw();
}
- fbo.unbind();
-
c.glFinish();
const fps = timer.read(); // ns
loops = (loops + 1) % 64;
@@ -171,18 +159,36 @@ pub fn main() !void {
}
control.dirty = false;
- }
+ break :blk true;
+ } else false;
+
+ var keep_running = false;
+ var i: usize = outputs.items.len;
+ while (i > 0) {
+ i -= 1;
+ const output = outputs.items[i];
+
+ var close_output = false;
+ if (output.update(fbo, is_fresh)) |res| {
+ if (res) |close| {
+ if (close) {
+ close_output = true;
+ } else {
+ keep_running = true;
+ }
+ }
+ } else |err| {
+ std.debug.print("Output {} closing due to error: {}\n", .{ output, err });
+ close_output = true;
+ }
- for (outputs.items, 0..) |output, i| {
- const close = output.update(fbo.texture_id);
- if (close) {
+ if (close_output) {
const removed = outputs.swapRemove(i);
removed.destroy(cfg_allocator);
- break;
}
}
- if (outputs.items.len == 0)
+ if (!keep_running)
break;
c.glfwMakeContextCurrent(window);
diff --git a/src/output.zig b/src/output.zig
index d15c0d4..e9785d2 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -5,7 +5,7 @@ const cfg = @import("config.zig");
const gl = @import("gl.zig");
pub const Output = struct {
- update_fn: *const fn (output: *Output, texture_id: c.GLuint) bool,
+ update_fn: *const fn (output: *Output, fbo: gl.FramebufferObject, fresh: bool) anyerror!?bool,
destroy_fn: *const fn (output: *Output, allocator: std.mem.Allocator) void,
pub fn create(
@@ -22,8 +22,8 @@ pub const Output = struct {
}
}
- pub fn update(self: *Output, texture_id: c.GLuint) bool {
- return self.update_fn(self, texture_id);
+ pub fn update(self: *Output, fbo: gl.FramebufferObject, fresh: bool) anyerror!?bool {
+ return self.update_fn(self, fbo, fresh);
}
pub fn destroy(self: *Output, allocator: std.mem.Allocator) void {
@@ -112,7 +112,7 @@ pub const WindowOutput = struct {
resized: bool = false,
- fn update(output: *Output, texture_id: c.GLuint) bool {
+ fn update(output: *Output, fbo: gl.FramebufferObject, _: bool) !?bool {
const self: *WindowOutput = @fieldParentPtr("output", output);
if (c.glfwWindowShouldClose(self.window) == c.GL_TRUE)
@@ -152,7 +152,7 @@ pub const WindowOutput = struct {
);
}
- c.glBindTexture(c.GL_TEXTURE_2D, texture_id);
+ c.glBindTexture(c.GL_TEXTURE_2D, fbo.texture_id);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
self.constants.texture_shader.bind();
@@ -210,3 +210,60 @@ pub const WindowOutput = struct {
_ = height;
}
};
+
+pub const StdoutOutput = struct {
+ pub const Config = struct {
+ pub const default: Config = .{};
+
+ pub fn create(
+ _: *const Config,
+ allocator: std.mem.Allocator,
+ constants: *gl.Constants,
+ ) !*Output {
+ const self = allocator.create(StdoutOutput) catch unreachable;
+
+ const buffer = try allocator.alloc(u8, @intCast(constants.config.width * constants.config.height * 4));
+ errdefer allocator.free(buffer);
+
+ const stdout = std.fs.File.stdout();
+
+ self.* = .{
+ .output = .{
+ .update_fn = update,
+ .destroy_fn = destroy,
+ },
+ .config = constants.config,
+ .buffer = buffer,
+ .file = stdout,
+ };
+
+ return &self.output;
+ }
+ };
+
+ output: Output,
+ config: *cfg.Config,
+ buffer: []u8,
+ file: std.fs.File,
+
+ fn update(output: *Output, fbo: gl.FramebufferObject, fresh: bool) !?bool {
+ const self: *StdoutOutput = @fieldParentPtr("output", output);
+
+ if (fresh) {
+ fbo.bind();
+ defer fbo.unbind();
+
+ fbo.read(self.config.width, self.config.height, self.buffer);
+ _ = try self.file.write(self.buffer);
+ }
+
+ return null;
+ }
+
+ fn destroy(output: *Output, allocator: std.mem.Allocator) void {
+ const self: *StdoutOutput = @fieldParentPtr("output", output);
+
+ allocator.free(self.buffer);
+ allocator.destroy(self);
+ }
+};
diff --git a/src/tsv.zig b/src/tsv.zig
index fb5db96..6381998 100644
--- a/src/tsv.zig
+++ b/src/tsv.zig
@@ -174,27 +174,29 @@ pub const TSVOutput = struct {
output: Output,
config: *const Config,
- fn update(output: *Output, texture_id: c.GLuint) bool {
+ fn update(output: *Output, fbo: gl.FramebufferObject, fresh: bool) !?bool {
const self: *TSVOutput = @fieldParentPtr("output", output);
- var fbo: c.GLint = undefined;
- c.glGetIntegerv(c.GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
+ if (fresh) {
+ var prev_fbo: c.GLint = undefined;
+ c.glGetIntegerv(c.GL_DRAW_FRAMEBUFFER_BINDING, &prev_fbo);
- switch (c.gl_client_send_image(
- get_or_init_client(),
- self.config.name,
- texture_id,
- c.GL_TEXTURE_2D,
- false,
- @intCast(fbo),
- null,
- )) {
- 1 => {},
- 0 => std.debug.print("tsv send: no remote image\n", .{}),
- else => |e| std.debug.print("tsv send: error {}\n", .{e}),
+ switch (c.gl_client_send_image(
+ get_or_init_client(),
+ self.config.name,
+ fbo.texture_id,
+ c.GL_TEXTURE_2D,
+ false,
+ @intCast(prev_fbo),
+ null,
+ )) {
+ 1 => {},
+ 0 => std.debug.print("tsv send: no remote image\n", .{}),
+ else => |e| std.debug.print("tsv send: error {}\n", .{e}),
+ }
}
- return false;
+ return null;
}
fn destroy(output: *Output, allocator: std.mem.Allocator) void {