diff --git a/src/bin/rec.rs b/src/bin/rec.rs index 646146e..8cdc50f 100644 --- a/src/bin/rec.rs +++ b/src/bin/rec.rs @@ -1,8 +1,9 @@ use std::env::args; use std::error::Error; -use std::fs; +use std::io::{stdout, Write}; use std::path::PathBuf; use std::sync::Arc; +use std::{fs, io}; use glam::{uvec2, UVec2}; use image::buffer::ConvertBuffer; @@ -11,22 +12,47 @@ use raytracing3::scene::{load_envmap, Renderer, SceneParams}; const SIZE: UVec2 = uvec2(1920, 1080); const FRAME_RATE: u32 = 60; -const DURATION_SECONDS: u32 = 120; -const N_FRAMES: u32 = DURATION_SECONDS * FRAME_RATE; const N_SPHERES: u32 = 100; const RAYS_PER_PIXEL: u32 = 1024; fn main() { - let args: Vec<_> = args().collect(); - let [_, path] = args.as_slice() else { - panic!("invalid arguments"); - }; - let path: PathBuf = path.into(); - fs::create_dir(&path).expect("failed to create the output directory"); + let path: PathBuf; + let start_frame; + let stop_frame; + match args().collect::>().as_slice() { + [_, apath] => { + path = apath.into(); + start_frame = 0; + stop_frame = 5; + } + [_, apath, aframes] => { + path = apath.into(); + start_frame = 0; + stop_frame = aframes.parse().unwrap(); + } + [_, apath, astart_frame, astop_frame] => { + path = apath.into(); + start_frame = astart_frame.parse().unwrap(); + stop_frame = astop_frame.parse().unwrap(); + } + _ => { + panic!("invalid arguments"); + } + } + println!( + "Rendering frames {start_frame} to {stop_frame} ({} total)", + stop_frame - start_frame + ); + match fs::create_dir(&path) { + Ok(_) => (), + Err(err) if err.kind() == io::ErrorKind::AlreadyExists => (), + Err(err) => panic!("failed to create the output directory: {err}"), + } + let n_threads = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(2); std::thread::scope(|s| { - let (img_sender, img_receiver) = async_channel::bounded::<(u32, Arc)>(50); - for _ in 0..16 { + let (img_sender, img_receiver) = async_channel::bounded::<(u32, Arc)>(2 * n_threads); + for _ in 0..n_threads { let img_receiver = img_receiver.clone(); let path = &path; s.spawn(move || { @@ -39,11 +65,11 @@ fn main() { } }); } - do_work(img_sender); + do_work(img_sender, start_frame, stop_frame); }); } -fn do_work(img_sender: async_channel::Sender<(u32, Arc)>) { +fn do_work(img_sender: async_channel::Sender<(u32, Arc)>, start_frame: u32, stop_frame: u32) { let img_sender = Arc::new(img_sender); let (device, queue) = pollster::block_on(init_gpu()).unwrap(); @@ -63,7 +89,11 @@ fn do_work(img_sender: async_channel::Sender<(u32, Arc)>) { let renderer = Renderer::new(&device, envmap); let presenter = Presenter::new(&device, output_format); - for frame in 0..N_FRAMES { + println!("Rendering..."); + for frame in start_frame..stop_frame { + if frame % FRAME_RATE == 0 { + println!("{frame}"); + } let output = device.create_texture(&wgpu::TextureDescriptor { label: None, size: texsize, @@ -136,8 +166,12 @@ fn do_work(img_sender: async_channel::Sender<(u32, Arc)>) { res.unwrap(); img_sender.send_blocking((frame, buffer)).unwrap(); }); + print!("."); + stdout().flush().unwrap(); } + println!("{stop_frame}"); device.poll(wgpu::Maintain::Wait); + println!("Done!"); } async fn init_gpu() -> Result<(wgpu::Device, wgpu::Queue), Box> {