const std = @import("std"); const build_config = @import("pardes_config"); const config = @import("config.zig"); const filesystem = @import("fs.zig"); const shader_dir = if (build_config.gui_shader_sources_prebuilt) "shaders/prebuilt/" else "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 post_vertex_path = shader_dir ++ "post.vert.glsl"; // The bundled post passes as compiled: the prefix and the pass together. const post_crt_path = shader_dir ++ "post-crt.frag.glsl"; const post_ripple_path = shader_dir ++ "post-ripple.frag.glsl"; const post_glitch_path = shader_dir ++ "post-glitch.frag.glsl"; pub const Backend = @TypeOf(build_config.platform); pub const backend: Backend = build_config.platform; pub const GuiShaderSourceMode = enum { live, prebuilt_snapshot, pub fn label(mode: GuiShaderSourceMode) []const u8 { return switch (mode) { .live => "live GLSL compiled during this build", .prebuilt_snapshot => "paired GLSL snapshot for committed SPIR-V", }; } }; /// Only the SDL backend consumes GLSL/SPIR-V. Other backends deliberately have /// no shader-source mode rather than being mislabeled "live" or "prebuilt". pub fn guiShaderSourceMode() ?GuiShaderSourceMode { if (backend != .gui) return null; return if (build_config.gui_shader_sources_prebuilt) .prebuilt_snapshot else .live; } 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/Post.zig", .contents = @embedFile("gui/Post.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 = post_vertex_path, .contents = @embedFile("effect-source-post.vert.glsl") }, .{ .path = post_crt_path, .contents = @embedFile("effect-source-post-crt.frag.glsl") }, .{ .path = post_ripple_path, .contents = @embedFile("effect-source-post-ripple.frag.glsl") }, .{ .path = post_glitch_path, .contents = @embedFile("effect-source-post-glitch.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{}, }; pub fn forSetting(setting: config.Runtime.Setting) ?[]const []const u8 { return switch (setting.action) { .transition => switch (backend) { .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 => |effect| switch (backend) { .gui => switch (effect) { .crt => &.{ "src/gui/Post.zig", "src/gui/gui.zig", post_vertex_path, post_crt_path }, .ripple => &.{ "src/gui/Post.zig", "src/gui/gui.zig", post_vertex_path, post_ripple_path }, .glitch => &.{ "src/gui/Post.zig", "src/gui/gui.zig", post_vertex_path, post_glitch_path }, }, .macos => &.{ "src/macos/Sources/PardesView.swift", "src/macos/Sources/ScenePostprocessor.swift", "shaders/crt.ci.metal" }, .tty, .web, .esp32p4 => null, }, else => null, }; } test "EffectCode paths resolve uniquely to this backend's archived inputs" { if (!@import("memory.zig").limits.embedded_sources) return error.SkipZigTest; 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)); }; } 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" { if (comptime backend == .gui) { const expected: GuiShaderSourceMode = if (build_config.gui_shader_sources_prebuilt) .prebuilt_snapshot else .live; try std.testing.expectEqual(expected, guiShaderSourceMode().?); try std.testing.expect(expected.label().len > 0); } else try std.testing.expect(guiShaderSourceMode() == null); }