summaryrefslogtreecommitdiff
path: root/src/detached/wire.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/detached/wire.zig')
-rw-r--r--src/detached/wire.zig71
1 files changed, 69 insertions, 2 deletions
diff --git a/src/detached/wire.zig b/src/detached/wire.zig
index 6903a1e8..ee8c72fb 100644
--- a/src/detached/wire.zig
+++ b/src/detached/wire.zig
@@ -3,6 +3,9 @@
const std = @import("std");
const pardes = @import("../pardes.zig");
const limits = @import("../memory.zig").limits;
+const shader_build = @import("../shader_build.zig");
+const Scene = pardes.config.Runtime.Scene;
+const ShaderAnimation = pardes.config.Runtime.ShaderAnimation;
/// 7: tag layers gained the `.notice` kind, so a frame can carry a tag value
/// an older frontend would reject mid-session. The greeting is where that has
@@ -73,6 +76,9 @@ pub const ServerTag = enum(u8) {
set_clipboard = 0x10,
read_clipboard = 0x11,
open_link = 0x12,
+ /// The post chain this frontend draws its frames through: sent on
+ /// attach and whenever it or a file's SPIR-V changes.
+ post = 0x13,
};
/// Why the server hung up on a connect. Sent as a `refuse` and followed by a
@@ -353,6 +359,22 @@ pub const ServerMsg = union(enum) {
set_clipboard: []const u8,
read_clipboard,
open_link: []const u8,
+ post: Post,
+};
+
+/// The session's post chain, as a GUI attached to it draws it: its passes in
+/// order, each a bundled scene at its level or a Shadertoy file's SPIR-V
+/// (compiled by the session, shader_build.zig: a frontend reads no disk and
+/// runs no program), and when it animates on its own. Slices borrow the
+/// payload.
+pub const Post = struct {
+ animation: ShaderAnimation = .on,
+ passes: [shader_build.max]shader_build.Pass = @splat(.{}),
+ len: u8 = 0,
+
+ pub fn list(p: *const Post) []const shader_build.Pass {
+ return p.passes[0..p.len];
+ }
};
// ---------------------------------------------------------------------------
@@ -1149,6 +1171,18 @@ pub fn encodeServer(out: []u8, msg: ServerMsg) Error![]const u8 {
.set_clipboard => |t| try w.putSlice32(t),
.read_clipboard => {},
.open_link => |u| try w.putSlice16(u),
+ .post => |p| {
+ try w.putByte(@intFromEnum(p.animation));
+ try w.putByte(p.len);
+ for (p.list()) |pass| {
+ // 0 a file, else a bundled scene and one.
+ try w.putByte(if (pass.scene) |scene| @as(u8, @intFromEnum(scene)) + 1 else 0);
+ try w.putByte(pass.level);
+ try w.putU32(pass.revision);
+ try w.putSlice16(pass.path);
+ try w.putSlice32(pass.spirv);
+ }
+ },
}
try finishMessage(&w, at);
return w.written();
@@ -1170,6 +1204,11 @@ pub fn serverBound(msg: ServerMsg) usize {
.frame => |f| frameBound(f.cols, f.rows),
.set_clipboard => |t| t.len,
.open_link => |u| u.len,
+ .post => |p| blk: {
+ var n: usize = 0;
+ for (p.list()) |pass| n += 12 + pass.path.len + pass.spirv.len;
+ break :blk n;
+ },
};
}
@@ -1232,6 +1271,22 @@ pub fn decodeServer(tag: u8, payload: []const u8) Error!ServerMsg {
.set_clipboard => .{ .set_clipboard = try r.getSlice32() },
.read_clipboard => .read_clipboard,
.open_link => .{ .open_link = try r.getSlice16() },
+ .post => blk: {
+ var p: Post = .{ .animation = try r.getTag(ShaderAnimation) };
+ p.len = try r.getByte();
+ if (p.len > shader_build.max) return error.Overlong;
+ for (p.passes[0..p.len]) |*pass| {
+ const kind = try r.getByte();
+ pass.* = .{
+ .scene = if (kind == 0) null else std.enums.fromInt(Scene, kind - 1) orelse return error.BadValue,
+ .level = try r.getByte(),
+ .revision = try r.getU32(),
+ .path = try r.getSlice16(),
+ .spirv = try r.getSlice32(),
+ };
+ }
+ break :blk .{ .post = p };
+ },
};
try r.end();
return msg;
@@ -1349,6 +1404,18 @@ test "detached wire: every server message round-trips" {
try testing.expectEqualStrings("yank", (try roundServer(&buf, .{ .set_clipboard = "yank" })).set_clipboard);
try testing.expectEqual(ServerMsg.read_clipboard, try roundServer(&buf, .read_clipboard));
try testing.expectEqualStrings("https://x", (try roundServer(&buf, .{ .open_link = "https://x" })).open_link);
+ var chain: Post = .{ .animation = .always, .len = 2 };
+ chain.passes[0] = .{ .scene = .bloom, .level = 3 };
+ chain.passes[1] = .{ .path = "~/wave.glsl", .spirv = "\x03\x02\x23\x07spirv", .revision = 7 };
+ const back = (try roundServer(&buf, .{ .post = chain })).post;
+ try testing.expectEqual(ShaderAnimation.always, back.animation);
+ try testing.expectEqual(@as(u8, 2), back.len);
+ try testing.expectEqual(Scene.bloom, back.passes[0].scene.?);
+ try testing.expectEqual(@as(u8, 3), back.passes[0].level);
+ try testing.expect(back.passes[1].scene == null);
+ try testing.expectEqualStrings("~/wave.glsl", back.passes[1].path);
+ try testing.expectEqualStrings("\x03\x02\x23\x07spirv", back.passes[1].spirv);
+ try testing.expectEqual(@as(u32, 7), back.passes[1].revision);
}
test "detached wire: only the display's own effects are on the wire" {
@@ -1357,9 +1424,9 @@ test "detached wire: only the display's own effects are on the wire" {
// is the direction that matters: it would hand a frontend work that must
// outlive it. The count fails if one of the three is dropped, which would
// silently leave a clipboard or a link unanswered on every frontend.
- try testing.expectEqual(@as(usize, 8), std.enums.values(ServerTag).len);
+ try testing.expectEqual(@as(usize, 9), std.enums.values(ServerTag).len);
for (std.enums.values(ServerTag)) |t| switch (t) {
- .welcome, .refuse, .frame, .quit, .detach, .set_clipboard, .read_clipboard, .open_link => {},
+ .welcome, .refuse, .frame, .quit, .detach, .set_clipboard, .read_clipboard, .open_link, .post => {},
};
}