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