Skip to main content

par_term_render/
shader_debug.rs

1//! Canonical locations of the shader debug dumps.
2//!
3//! Two components write these files — the transpiler dumps the wrapped GLSL it
4//! feeds to naga, and the custom-shader renderer dumps the WGSL naga produces —
5//! and several more report the paths to the user through shader diagnostics and
6//! the AI inspector. They used to disagree: the renderer hardcoded `/tmp` on
7//! Unix while the transpiler used the system temp directory, so on macOS the
8//! reported wrapped-GLSL path pointed somewhere the file had never been
9//! written. Everything now resolves through this module.
10
11use std::path::{Path, PathBuf};
12
13/// File name of the wrapped-GLSL dump written by the transpiler in debug builds.
14pub const WRAPPED_GLSL_FILE_NAME: &str = "par_term_debug_wrapped.glsl";
15
16/// Directory the shader debug dumps are written to.
17///
18/// This is [`std::env::temp_dir`]: `$TMPDIR` where set, a per-user directory on
19/// macOS, `%TEMP%` on Windows. Deliberately not a hardcoded `/tmp` — that is not
20/// even an absolute path on Windows, and a predictable name in a world-writable
21/// directory is a symlink hazard on multi-user systems, which is why the
22/// transpiler dump is written `0600`.
23pub fn debug_dump_dir() -> PathBuf {
24    std::env::temp_dir()
25}
26
27/// Path of the transpiled-WGSL dump for `shader_name`.
28///
29/// `shader_name` may be a bare name or a path; only the file stem is used, so
30/// `crt`, `crt.glsl` and `~/.config/par-term/shaders/crt.glsl` all resolve to
31/// the same dump.
32pub fn transpiled_wgsl_path(shader_name: &str) -> PathBuf {
33    let stem = Path::new(shader_name)
34        .file_stem()
35        .and_then(|s| s.to_str())
36        .unwrap_or(shader_name);
37    debug_dump_dir().join(format!("par_term_{stem}_shader.wgsl"))
38}
39
40/// Path of the wrapped-GLSL dump the transpiler writes in debug builds.
41pub fn wrapped_glsl_path() -> PathBuf {
42    debug_dump_dir().join(WRAPPED_GLSL_FILE_NAME)
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[test]
50    fn dumps_land_in_the_system_temp_dir() {
51        assert!(transpiled_wgsl_path("crt").starts_with(std::env::temp_dir()));
52        assert!(wrapped_glsl_path().starts_with(std::env::temp_dir()));
53    }
54
55    #[test]
56    fn shader_name_is_reduced_to_its_stem() {
57        let expected = debug_dump_dir().join("par_term_crt_shader.wgsl");
58        assert_eq!(transpiled_wgsl_path("crt"), expected);
59        assert_eq!(transpiled_wgsl_path("crt.glsl"), expected);
60        assert_eq!(
61            transpiled_wgsl_path("/home/u/.config/par-term/shaders/crt.glsl"),
62            expected
63        );
64    }
65
66    /// The renderer and the transpiler must agree, and both must agree with
67    /// what shader diagnostics reports — the drift this module exists to stop.
68    #[test]
69    fn both_dump_kinds_share_one_directory() {
70        assert_eq!(
71            transpiled_wgsl_path("crt").parent(),
72            wrapped_glsl_path().parent()
73        );
74    }
75}