summaryrefslogtreecommitdiff
path: root/src/effect_sources.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/effect_sources.zig')
-rw-r--r--src/effect_sources.zig273
1 files changed, 62 insertions, 211 deletions
diff --git a/src/effect_sources.zig b/src/effect_sources.zig
index d4f0e38b..3ca15c3f 100644
--- a/src/effect_sources.zig
+++ b/src/effect_sources.zig
@@ -1,100 +1,18 @@
-//! Build-embedded source behind EffectCode.
-//!
-//! Several builtins intentionally share one shader pass. Returning segments
-//! makes that sharing visible instead of copying or manufacturing a pretend
-//! per-effect program.
-
const std = @import("std");
const build_config = @import("pardes_config");
-const runtime_config = @import("runtime_config.zig");
-
-const panel_math = @embedFile("panel_animation.zig");
-const pardes_core = @embedFile("pardes.zig");
-const tty_compositor = @embedFile("tty/panel_compositor.zig");
-const panel_vertex = @embedFile("effect-source-ui.vert.glsl");
-const panel_fragment = @embedFile("effect-source-ui.frag.glsl");
-const image_vertex = @embedFile("effect-source-image.vert.glsl");
-const image_fragment = @embedFile("effect-source-image.frag.glsl");
-const scene_vertex = @embedFile("effect-source-crt.vert.glsl");
-const scene_fragment = @embedFile("effect-source-crt.frag.glsl");
-const gui_scene_mapping = @embedFile("gui/crt.zig");
-const gui_host = @embedFile("gui/gui.zig");
-const mac_scene = @embedFile("effect-source-crt.ci.metal");
-const mac_postprocessor = @embedFile("macos/Sources/ScenePostprocessor.swift");
-const mac_view = @embedFile("macos/Sources/PardesView.swift");
-
-fn sourceSection(
- comptime source: []const u8,
- comptime begin_marker: []const u8,
- comptime end_marker: []const u8,
-) []const u8 {
- // gui.zig is intentionally embedded as the source actually compiled, then
- // narrowed to its marked host paths. The comptime byte scan is larger than
- // Zig's small default quota but contributes no runtime work.
- @setEvalBranchQuota(1_000_000);
- const begin = std.mem.indexOf(u8, source, begin_marker) orelse
- @compileError("EffectCode source begin marker is missing");
- const body = begin + begin_marker.len;
- const end = std.mem.indexOfPos(u8, source, body, end_marker) orelse
- @compileError("EffectCode source end marker is missing");
- return source[body..end];
-}
+const config = @import("config.zig");
+const filesystem = @import("fs.zig");
-const gui_panel_host = sourceSection(
- gui_host,
- "// EFFECT_CODE_PANEL_HOST_BEGIN\n",
- "// EFFECT_CODE_PANEL_HOST_END",
-);
-const gui_native_panel = sourceSection(
- gui_host,
- "// EFFECT_CODE_NATIVE_PANEL_BEGIN\n",
- "// EFFECT_CODE_NATIVE_PANEL_END",
-);
-const gui_frame_submission = sourceSection(
- gui_host,
- "// EFFECT_CODE_FRAME_SUBMISSION_BEGIN\n",
- "// EFFECT_CODE_FRAME_SUBMISSION_END",
-);
-const gui_cell_instance = sourceSection(
- gui_host,
- "// EFFECT_CODE_CELL_INSTANCE_BEGIN\n",
- "// EFFECT_CODE_CELL_INSTANCE_END",
-);
-const ascii_diff = sourceSection(
- pardes_core,
- "// EFFECT_CODE_ASCII_DIFF_BEGIN\n",
- "// EFFECT_CODE_ASCII_DIFF_END",
-);
-const ascii_compositor = sourceSection(
- pardes_core,
- " // EFFECT_CODE_ASCII_COMPOSITOR_BEGIN\n",
- " // EFFECT_CODE_ASCII_COMPOSITOR_END",
-);
-
-const ui_vertex_path = if (build_config.gui_shader_sources_prebuilt)
- "shaders/prebuilt/ui.vert.glsl"
-else
- "shaders/ui.vert.glsl";
-const ui_fragment_path = if (build_config.gui_shader_sources_prebuilt)
- "shaders/prebuilt/ui.frag.glsl"
-else
- "shaders/ui.frag.glsl";
-const image_vertex_path = if (build_config.gui_shader_sources_prebuilt)
- "shaders/prebuilt/image.vert.glsl"
-else
- "shaders/image.vert.glsl";
-const image_fragment_path = if (build_config.gui_shader_sources_prebuilt)
- "shaders/prebuilt/image.frag.glsl"
+const shader_dir = if (build_config.gui_shader_sources_prebuilt)
+ "shaders/prebuilt/"
else
- "shaders/image.frag.glsl";
-const scene_vertex_path = if (build_config.gui_shader_sources_prebuilt)
- "shaders/prebuilt/crt.vert.glsl"
-else
- "shaders/crt.vert.glsl";
-const scene_fragment_path = if (build_config.gui_shader_sources_prebuilt)
- "shaders/prebuilt/crt.frag.glsl"
-else
- "shaders/crt.frag.glsl";
+ "shaders/";
+const ui_vertex_path = shader_dir ++ "ui.vert.glsl";
+const ui_fragment_path = shader_dir ++ "ui.frag.glsl";
+const image_vertex_path = shader_dir ++ "image.vert.glsl";
+const image_fragment_path = shader_dir ++ "image.frag.glsl";
+const scene_vertex_path = shader_dir ++ "crt.vert.glsl";
+const scene_fragment_path = shader_dir ++ "crt.frag.glsl";
pub const Backend = @TypeOf(build_config.platform);
pub const backend: Backend = build_config.platform;
@@ -121,120 +39,72 @@ pub fn guiShaderSourceMode() ?GuiShaderSourceMode {
.live;
}
-pub const Segment = struct {
- path: []const u8,
- source: []const u8,
+pub const files = switch (backend) {
+ .tty => [_]filesystem.Source{
+ .{ .path = "src/tty/panel_compositor.zig", .contents = @embedFile("tty/panel_compositor.zig") },
+ },
+ .gui => [_]filesystem.Source{
+ .{ .path = "src/gui/gui.zig", .contents = @embedFile("gui/gui.zig") },
+ .{ .path = "src/gui/crt.zig", .contents = @embedFile("gui/crt.zig") },
+ .{ .path = ui_vertex_path, .contents = @embedFile("effect-source-ui.vert.glsl") },
+ .{ .path = ui_fragment_path, .contents = @embedFile("effect-source-ui.frag.glsl") },
+ .{ .path = image_vertex_path, .contents = @embedFile("effect-source-image.vert.glsl") },
+ .{ .path = image_fragment_path, .contents = @embedFile("effect-source-image.frag.glsl") },
+ .{ .path = scene_vertex_path, .contents = @embedFile("effect-source-crt.vert.glsl") },
+ .{ .path = scene_fragment_path, .contents = @embedFile("effect-source-crt.frag.glsl") },
+ },
+ .macos => [_]filesystem.Source{
+ .{ .path = "src/macos/Sources/PardesView.swift", .contents = @embedFile("macos/Sources/PardesView.swift") },
+ .{ .path = "src/macos/Sources/ScenePostprocessor.swift", .contents = @embedFile("macos/Sources/ScenePostprocessor.swift") },
+ .{ .path = "shaders/crt.ci.metal", .contents = @embedFile("effect-source-crt.ci.metal") },
+ },
+ .web, .esp32p4 => [_]filesystem.Source{},
};
-const tty_panel = [_]Segment{
- .{ .path = "src/panel_animation.zig", .source = panel_math },
- .{ .path = "src/pardes.zig#ascii-diff", .source = ascii_diff },
- .{ .path = "src/pardes.zig#ascii-compositor", .source = ascii_compositor },
- .{ .path = "src/tty/panel_compositor.zig", .source = tty_compositor },
-};
-const gui_panel = [_]Segment{
- .{ .path = "src/panel_animation.zig", .source = panel_math },
- .{ .path = "src/pardes.zig#ascii-diff", .source = ascii_diff },
- .{ .path = "src/pardes.zig#ascii-compositor", .source = ascii_compositor },
- .{ .path = "src/gui/gui.zig#panel-host", .source = gui_panel_host },
- .{ .path = "src/gui/gui.zig#native-panel", .source = gui_native_panel },
- .{ .path = "src/gui/gui.zig#frame-submission", .source = gui_frame_submission },
- .{ .path = "src/gui/gui.zig#cell-instance", .source = gui_cell_instance },
- .{ .path = ui_vertex_path, .source = panel_vertex },
- .{ .path = ui_fragment_path, .source = panel_fragment },
- .{ .path = image_vertex_path, .source = image_vertex },
- .{ .path = image_fragment_path, .source = image_fragment },
-};
-const gui_scene = [_]Segment{
- .{ .path = "src/gui/crt.zig", .source = gui_scene_mapping },
- .{ .path = "src/gui/gui.zig#frame-submission", .source = gui_frame_submission },
- .{ .path = scene_vertex_path, .source = scene_vertex },
- .{ .path = scene_fragment_path, .source = scene_fragment },
-};
-const mac_panel = [_]Segment{
- .{ .path = "src/panel_animation.zig", .source = panel_math },
- .{ .path = "src/pardes.zig#ascii-diff", .source = ascii_diff },
- .{ .path = "src/pardes.zig#ascii-compositor", .source = ascii_compositor },
- .{ .path = "src/macos/Sources/PardesView.swift", .source = mac_view },
- .{ .path = "src/macos/Sources/ScenePostprocessor.swift", .source = mac_postprocessor },
- .{ .path = "shaders/crt.ci.metal", .source = mac_scene },
-};
-const mac_scene_segments = [_]Segment{
- .{ .path = "src/macos/Sources/PardesView.swift", .source = mac_view },
- .{ .path = "src/macos/Sources/ScenePostprocessor.swift", .source = mac_postprocessor },
- .{ .path = "shaders/crt.ci.metal", .source = mac_scene },
-};
-
-/// Sources for the backend this executable was built for. Keeping the backend
-/// compile-time and out of the call signature is important: a TTY binary must
-/// not carry the macOS host and Metal source merely because another switch arm
-/// could have returned them.
-pub fn forSetting(setting: runtime_config.Setting) ?[]const Segment {
+pub fn forSetting(setting: config.Runtime.Setting) ?[]const []const u8 {
return switch (setting.action) {
.transition => switch (backend) {
- .tty => &tty_panel,
- .gui => &gui_panel,
- .macos => &mac_panel,
+ .tty => &.{ "src/layout.zig", "src/pardes.zig", "src/tty/panel_compositor.zig" },
+ .gui => &.{ "src/layout.zig", "src/pardes.zig", "src/gui/gui.zig", ui_vertex_path, ui_fragment_path, image_vertex_path, image_fragment_path },
+ .macos => &.{ "src/layout.zig", "src/pardes.zig", "src/macos/Sources/PardesView.swift", "src/macos/Sources/ScenePostprocessor.swift", "shaders/crt.ci.metal" },
.web, .esp32p4 => null,
},
.scene => switch (backend) {
- .gui => &gui_scene,
- .macos => &mac_scene_segments,
+ .gui => &.{ "src/gui/crt.zig", "src/gui/gui.zig", scene_vertex_path, scene_fragment_path },
+ .macos => &.{ "src/macos/Sources/PardesView.swift", "src/macos/Sources/ScenePostprocessor.swift", "shaders/crt.ci.metal" },
.tty, .web, .esp32p4 => null,
},
else => null,
};
}
-test "every current-backend effect exposes embedded implementation code" {
- for (runtime_config.settings) |setting| switch (setting.action) {
- .transition => if (backend != .web) {
- const segments = forSetting(setting) orelse return error.MissingTransitionSource;
- for (segments) |segment| {
- try std.testing.expect(segment.path.len > 0);
- try std.testing.expect(segment.source.len > 0);
- }
- } else try std.testing.expect(forSetting(setting) == null),
- .scene => if (backend == .gui or backend == .macos) {
- const segments = forSetting(setting) orelse return error.MissingSceneSource;
- for (segments) |segment| {
- try std.testing.expect(segment.path.len > 0);
- try std.testing.expect(segment.source.len > 0);
- }
- } else try std.testing.expect(forSetting(setting) == null),
- else => {},
- };
-}
-
-test "GUI scene EffectCode includes both runtime shader stages" {
- if (comptime backend == .gui) {
- try std.testing.expectEqual(@as(usize, 4), gui_scene.len);
- try std.testing.expectEqualStrings("src/gui/crt.zig", gui_scene[0].path);
- try std.testing.expectEqualStrings("src/gui/gui.zig#frame-submission", gui_scene[1].path);
- try std.testing.expectEqualStrings(scene_vertex_path, gui_scene[2].path);
- try std.testing.expectEqualStrings(scene_fragment_path, gui_scene[3].path);
- try std.testing.expect(std.mem.indexOf(u8, gui_scene[0].source, "pub fn mapScene") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_scene[1].source, "SDL_PushGPUFragmentUniformData") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_scene[2].source, "gl_VertexIndex") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_scene[3].source, "u_crt.effects") != null);
+test "EffectCode paths resolve uniquely to this backend's archived inputs" {
+ for (config.Runtime.settings) |setting| {
+ const available = switch (setting.action) {
+ .transition => backend == .tty or backend == .gui or backend == .macos,
+ .scene => backend == .gui or backend == .macos,
+ else => false,
+ };
+ const paths = forSetting(setting);
+ try std.testing.expectEqual(available, paths != null);
+ if (paths) |listed| for (listed, 0..) |path, i| {
+ const bytes = filesystem.sourceBytes(path) orelse return error.MissingEffectSource;
+ try std.testing.expect(bytes.len > 0);
+ for (listed[0..i]) |previous| try std.testing.expect(!std.mem.eql(u8, path, previous));
+ };
}
-}
-
-test "GUI panel EffectCode includes the actual host paint and submission path" {
- if (comptime backend == .gui) {
- try std.testing.expect(std.mem.indexOf(u8, ascii_diff, "pub const PanelCellDiff") != null);
- try std.testing.expect(std.mem.indexOf(u8, ascii_compositor, "fn composeAsciiTransitions") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_panel_host, "fn makePaintPlan") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_panel_host, "fn setTransitionFields") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_native_panel, "fn prepareNativeImages") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_native_panel, "fn drawNativeImagesGpu") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_native_panel, "active.visualBox()") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_frame_submission, "for (paint_plan.batches") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_cell_instance, "fn emitInstance") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_cell_instance, "setTransitionFields") != null);
- try std.testing.expect(std.mem.indexOf(u8, panel_math, "frame_count") != null);
- try std.testing.expect(std.mem.indexOf(u8, gui_frame_submission, "active.effect == .dissolve") != null);
+ for (files) |file| {
+ const archived = filesystem.sourceBytes(file.path) orelse return error.MissingEffectSource;
+ try std.testing.expectEqualStrings(file.contents, archived);
+ var matches: usize = 0;
+ for (filesystem.sources) |source| if (std.mem.eql(u8, source.path, file.path)) {
+ matches += 1;
+ };
+ try std.testing.expectEqual(@as(usize, 1), matches);
}
+ try std.testing.expectEqual(backend == .tty, filesystem.sourceBytes("src/tty/panel_compositor.zig") != null);
+ try std.testing.expectEqual(backend == .gui, filesystem.sourceBytes("src/gui/gui.zig") != null);
+ try std.testing.expectEqual(backend == .macos, filesystem.sourceBytes("src/macos/Sources/PardesView.swift") != null);
}
test "shader source provenance is GUI-only and follows the build input" {
@@ -247,22 +117,3 @@ test "shader source provenance is GUI-only and follows the build input" {
try std.testing.expect(expected.label().len > 0);
} else try std.testing.expect(guiShaderSourceMode() == null);
}
-
-test "mac EffectCode includes the runtime panel and scene wiring" {
- if (comptime backend == .macos) {
- // `extern "C" [[stitchable]]` is what the runtime compile requires:
- // CIKernel.kernels(withMetalString:) looks for stitchable functions and
- // rejects the whole source without them, so ScenePostprocessor.init?
- // returns nil and every scene effect and panel transition silently
- // degrades to the plain CoreText draw. The spelling is pinned on
- // purpose; relaxing these three matches is how that comes back.
- try std.testing.expect(std.mem.indexOf(u8, mac_scene, "extern \"C\" [[stitchable]] float4 pardesPanelClear") != null);
- try std.testing.expect(std.mem.indexOf(u8, mac_scene, "extern \"C\" [[stitchable]] float4 pardesPanel") != null);
- try std.testing.expect(std.mem.indexOf(u8, mac_scene, "extern \"C\" [[stitchable]] float4 pardesScene") != null);
- try std.testing.expect(std.mem.indexOf(u8, mac_scene, "already composed in Pardes core") != null);
- try std.testing.expect(std.mem.indexOf(u8, mac_view, "hideCursor: !tracks.isEmpty") != null);
- try std.testing.expect(std.mem.indexOf(u8, mac_postprocessor, "panelClearKernel.apply") != null);
- try std.testing.expect(std.mem.indexOf(u8, mac_postprocessor, "panelKernel.apply") != null);
- try std.testing.expect(std.mem.indexOf(u8, mac_postprocessor, "sceneKernel.apply") != null);
- }
-}