yum/vfft
git clone https://git.yummers.dev/yum/vfft
4c5f4de
master
1use anyhow:: Context ; 2use std:: fs; 3use std:: fs:: File ; 4use std:: fs:: OpenOptions ; 5use std:: io:: Write ; 6use std:: path::{ Path , PathBuf }; 7use std:: process::{ Command , Output }; 8 9fn say ( message : & str ) { 10let file =OpenOptions :: new (). write ( true ). open ( "/dev/tty" ); 11if file. is_ok () { 12let _ =writeln! ( file. unwrap (), "gpu_fft: {message}" ); 13} 14} 15 16fn run_cmd ( cmd : & str , dir : & Path ) -> anyhow:: Result < Output > { 17println! ( "cargo::warning=Running {cmd}..." ); 18let output =Command :: new ( "sh" ) 19. arg ( "-c" ) 20. arg ( cmd) 21. current_dir ( dir) 22. output () 23. with_context ( ||format! ( "failed to execute `{cmd}`" )) ?; 24 25if !output. status . success () { 26 anyhow:: bail!( 27"Command failed `{cmd}`:\nstdout:{}\nstderr:\n{}" , 28String :: from_utf8_lossy ( & output. stdout ), 29String :: from_utf8_lossy ( & output. stderr ) 30); 31} 32 33Ok ( output) 34} 35 36fn ensure_slang ( slang_dir : & Path ) ->Result < PathBuf , anyhow:: Error > { 37let sentinel = slang_dir. join ( ".did_build" ); 38let slangc = slang_dir. join ( "build/RelWithDebInfo/bin/slangc" ); 39if sentinel. exists () { 40// Already built - short-circuit. 41return Ok ( slangc); 42} 43 44say ( concat! ( 45"The slang compiler is not present, or is missing the\n" , 46"sentinel file. We need the slang compiler in order to translate\n" , 47".slang shaders into .wgsl, which wgpu (webGPU) uses. We're going to\n" , 48"acquire the slang compiler, then build it. This will take a few\n" , 49"minutes and use a lot of CPU. This only needs to run once." 50)); 51 52// Assume we're in some weird intermediate state and start fresh. 53if slang_dir. exists () { 54say ( "Removing old slang compiler..." ); 55 fs:: remove_dir_all ( slang_dir) ?; 56} 57 58say ( "cargo::warning=Acquiring slang compiler..." ); 59let clone_ret =Command :: new ( "git" ) 60. args ([ 61"clone" , 62"--recursive" , 63"https://github.com/shader-slang/slang" , 64]) 65. arg ( slang_dir) 66. status () ?; 67 anyhow:: ensure!( clone_ret. success (), "Failed to clone slang" ); 68run_cmd ( "mkdir build" , slang_dir) ?; 69 70say ( "Building slang compiler..." ); 71run_cmd ( "cmake -B build --preset default" , slang_dir) ?; 72run_cmd ( "cmake --build --preset releaseWithDebugInfo" , slang_dir) ?; 73File :: create ( sentinel) ?; 74Ok ( slangc) 75} 76 77// Convert slang shaders in shaders/ to wgsl. (I refuse to use the term "transpile" - it is 78// redundant and ignores the fact that all compilation is merely a translation from one language to 79// another.) 80fn compile_shaders ( 81slangc : & PathBuf , 82slang_dir : & Path , 83wgsl_dir : & PathBuf , 84) ->Result <(), anyhow:: Error > { 85if Path :: new ( wgsl_dir). exists () { 86 fs:: remove_dir_all ( wgsl_dir) ?; 87} 88 fs:: create_dir_all ( wgsl_dir) 89. with_context ( ||format! ( "Failed to create output directory {wgsl_dir:?}" )) ?; 90 91for entryin fs:: read_dir ( slang_dir) ?{ 92let entry = entry?. path (); 93let Some ( ext) = entry. extension () else { 94// No extension. 95continue ; 96}; 97if ext !="slang" { 98continue ; 99} 100let stem = entry 101. file_stem () 102. with_context ( ||format! ( "Failed to get file stem for {}" , entry. display ())) ?; 103let new_path =Path :: new ( wgsl_dir). join ( stem). with_extension ( "wgsl" ); 104let slang_dir = entry. parent (). ok_or ( anyhow:: anyhow!( 105"Failed to get parent directory for {}" , 106 entry. display () 107)) ?; 108let compile_ret =Command :: new ( slangc) 109. arg ( & entry) 110. arg ( "-o" ) 111. arg ( & new_path) 112. arg ( "-no-mangle" ) 113. arg ( "-I" ) 114. arg ( slang_dir) 115. status () ?; 116 anyhow:: ensure!( compile_ret. success (), "Failed to compile shader" ); 117} 118 119Ok (()) 120} 121 122fn main () -> anyhow:: Result <()> { 123if std:: env:: var_os ( "CARGO_FEATURE_GPU" ). is_none () { 124return Ok (()); 125} 126 127let out =PathBuf :: from ( std:: env:: var_os ( "OUT_DIR" ). unwrap ()); 128let slangc =ensure_slang ( & out. join ( "slang" )) ?; 129 130println! ( "cargo:rerun-if-changed=shaders" ); 131compile_shaders ( & slangc, Path :: new ( "./shaders" ), & out. join ( "shaders" )) ?; 132 133Ok (()) 134}