yum/gpu_fft
A GPU-friendly FFT
git clone https://git.yummers.dev/yum/gpu_fft
69b4543
master
1use anyhow:: Context ; 2use std:: fs; 3use std:: fs:: File ; 4use std:: fs:: OpenOptions ; 5use std:: io:: Write ; 6use std:: path:: Path ; 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 : & str ) -> 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 () ->Result <(), anyhow:: Error > { 37let sentinel ="./slang/.did_build" ; 38if Path :: new ( sentinel). exists () { 39// Already built - short-circuit. 40return Ok (()); 41} 42 43say ( concat! ( 44"The slang compiler is not present, or is missing the\n" , 45"sentinel file. We need the slang compiler in order to translate\n" , 46".slang shaders into .wgsl, which wgpu (webGPU) uses. We're going to\n" , 47"acquire the slang compiler, then build it. This will take a few\n" , 48"minutes and use a lot of CPU. This only needs to run once." 49)); 50 51// Assume we're in some weird intermediate state and start fresh. 52if Path :: new ( "./slang" ). exists () { 53say ( "Removing old slang compiler..." ); 54 fs:: remove_dir_all ( "./slang" ) ?; 55} 56 57say ( "cargo::warning=Acquiring slang compiler..." ); 58run_cmd ( 59"git clone --recursive https://github.com/shader-slang/slang" , 60"." , 61) ?; 62run_cmd ( "mkdir ./slang/build" , "." ) ?; 63 64say ( "Building slang compiler..." ); 65run_cmd ( "cmake -B build --preset default" , "./slang" ) ?; 66run_cmd ( "cmake --build --preset releaseWithDebugInfo" , "./slang" ) ?; 67File :: create ( sentinel) ?; 68Ok (()) 69} 70 71// Convert slang shaders in shaders/ to wgsl. (I refuse to use the term "transpile" - it is 72// redundant and ignores the fact that all compilation is merely a translation from one language to 73// another.) 74fn compile_shaders ( slang_dir : & str , wgsl_dir : & str ) ->Result <(), anyhow:: Error > { 75let compiler_path ="./slang/build/RelWithDebInfo/bin/slangc" ; 76 77if Path :: new ( wgsl_dir). exists () { 78 fs:: remove_dir_all ( wgsl_dir) ?; 79} 80 fs:: create_dir_all ( wgsl_dir) 81. with_context ( ||format! ( "Failed to create output directory {wgsl_dir}" )) ?; 82 83for entryin fs:: read_dir ( slang_dir) ?{ 84let entry = entry?. path (); 85let Some ( ext) = entry. extension () else { 86// No extension. 87continue ; 88}; 89if ext !="slang" { 90continue ; 91} 92let stem = entry 93. file_stem () 94. with_context ( ||format! ( "Failed to get file stem for {}" , entry. display ())) ?; 95let new_path =Path :: new ( wgsl_dir). join ( stem). with_extension ( "wgsl" ); 96let slang_dir = entry. parent (). ok_or ( anyhow:: anyhow!( 97"Failed to get parent directory for {}" , 98 entry. display () 99)) ?; 100let cmd =format! ( 101"{compiler_path} {} -o {} -no-mangle -I {}" , 102 entry. display (), 103 new_path. display (), 104 slang_dir. display (), 105); 106run_cmd ( & cmd, "." ) ?; 107} 108 109Ok (()) 110} 111 112fn main () -> anyhow:: Result <()> { 113println! ( "cargo:rerun-if-changed=slang" ); 114ensure_slang () ?; 115 116println! ( "cargo:rerun-if-changed=shaders" ); 117compile_shaders ( "./shaders" , "./src/generated/shaders" ) ?; 118 119Ok (()) 120}