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}