diff options
Diffstat (limited to 'racer-tracer/src')
| -rw-r--r-- | racer-tracer/src/config.rs | 3 | ||||
| -rw-r--r-- | racer-tracer/src/image.rs | 65 | ||||
| -rw-r--r-- | racer-tracer/src/main.rs | 89 | ||||
| -rw-r--r-- | racer-tracer/src/render.rs | 227 |
4 files changed, 186 insertions, 198 deletions
diff --git a/racer-tracer/src/config.rs b/racer-tracer/src/config.rs index 79c50eb..cf747ec 100644 --- a/racer-tracer/src/config.rs +++ b/racer-tracer/src/config.rs @@ -14,7 +14,8 @@ pub struct Screen { pub struct RenderData { pub samples: usize, pub max_depth: usize, - pub recurse_depth: usize, + pub num_threads_width: usize, + pub num_threads_height: usize, pub scale: usize, } diff --git a/racer-tracer/src/image.rs b/racer-tracer/src/image.rs index 1df4cc5..094b1f8 100644 --- a/racer-tracer/src/image.rs +++ b/racer-tracer/src/image.rs @@ -1,3 +1,4 @@ +#[derive(Clone)] pub struct Image { pub aspect_ratio: f64, pub width: usize, @@ -14,20 +15,6 @@ impl Image { } } -// TODO: SubImage and Image can probably be the same struct -impl From<&Image> for SubImage { - fn from(image: &Image) -> Self { - SubImage { - x: 0, - y: 0, - width: image.width, - height: image.height, - screen_width: image.width, - screen_height: image.height, - } - } -} - pub struct SubImage { pub x: usize, pub y: usize, @@ -36,53 +23,3 @@ pub struct SubImage { pub width: usize, pub height: usize, } - -pub trait QuadSplit { - fn quad_split(&self) -> [SubImage; 4]; -} - -impl QuadSplit for SubImage { - fn quad_split(&self) -> [SubImage; 4] { - let half_w = self.width / 2; - let half_h = self.height / 2; - - [ - // Top Left - SubImage { - x: self.x, - y: self.y, - width: half_w, - height: half_h, - screen_width: self.screen_width, - screen_height: self.screen_height, - }, - // Top Right - SubImage { - x: self.x + half_w, - y: self.y, - width: half_w, - height: half_h, - screen_width: self.screen_width, - screen_height: self.screen_height, - }, - // Bottom Left - SubImage { - x: self.x, - y: self.y + half_h, - width: half_w, - height: half_h, - screen_width: self.screen_width, - screen_height: self.screen_height, - }, - // Bottom Right - SubImage { - x: self.x + half_w, - y: self.y + half_h, - width: half_w, - height: half_h, - screen_width: self.screen_width, - screen_height: self.screen_height, - }, - ] - } -} diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs index d97e3a1..b441dd0 100644 --- a/racer-tracer/src/main.rs +++ b/racer-tracer/src/main.rs @@ -13,7 +13,7 @@ mod vec3; use std::{ convert::TryFrom, - sync::{Arc, Mutex, RwLock}, + sync::RwLock, time::{Duration, Instant}, vec::Vec, }; @@ -25,38 +25,27 @@ use crate::{ camera::Camera, config::{Args, Config}, error::TracerError, - geometry::Hittable, - image::SubImage, render::render, scene::Scene, }; fn run(config: Config) -> Result<(), TracerError> { - let preview_render_data = Arc::new(config.preview); - let render_data = Arc::new(config.render); + let preview_render_data = config.preview; + let render_data = config.render; let image = image::Image::new(config.screen.width, config.screen.height); - let camera = Arc::new(RwLock::new(Camera::new(&image, 2.0, 1.0))); - let scene: Arc<Box<dyn Hittable>> = Arc::new(Box::new( - config - .scene - .ok_or(TracerError::NoScene()) - .and_then(Scene::from_file)?, - )); - let screen_buffer: Arc<RwLock<Vec<u32>>> = - Arc::new(RwLock::new(vec![0; image.width * image.height])); + let camera = RwLock::new(Camera::new(&image, 2.0, 1.0)); + let scene: Scene = config + .scene + .ok_or(TracerError::NoScene()) + .and_then(Scene::from_file)?; + let screen_buffer: RwLock<Vec<u32>> = RwLock::new(vec![0; image.width * image.height]); - let window_res: Arc<Mutex<Result<(), TracerError>>> = Arc::new(Mutex::new(Ok(()))); - let sub_image: SubImage = (&image).into(); - let move_camera = Arc::clone(&camera); + let mut window_res: Result<(), TracerError> = Ok(()); + let move_camera = &camera; - let render_image = Arc::new(SignalEvent::manual(false)); - let window_render_image = Arc::clone(&render_image); - - let cancel_render = Arc::new(SignalEvent::manual(false)); - let window_cancel_render = cancel_render.clone(); - - let exit = Arc::new(SignalEvent::manual(false)); - let window_exit = Arc::clone(&exit); + let render_image = SignalEvent::manual(false); + let cancel_render = SignalEvent::manual(false); + let exit = SignalEvent::manual(false); rayon::scope(|s| { s.spawn(|_| { @@ -67,15 +56,14 @@ fn run(config: Config) -> Result<(), TracerError> { if render_image.wait_timeout(Duration::from_secs(0)) && render_image.status() { let render_time = Instant::now(); - let cancel_render_event = Arc::clone(&cancel_render); render( - Arc::clone(&screen_buffer), - Arc::clone(&camera), - &sub_image, - Arc::clone(&scene), - Arc::clone(&render_data), - render_data.recurse_depth, - Some(cancel_render_event), + &screen_buffer, + &camera, + &image, + &scene, + &render_data, + Some(&cancel_render), + None, ); println!( @@ -85,19 +73,19 @@ fn run(config: Config) -> Result<(), TracerError> { } else { // Render preview render( - Arc::clone(&screen_buffer), - Arc::clone(&camera), - &sub_image, - Arc::clone(&scene), - Arc::clone(&preview_render_data), - preview_render_data.recurse_depth, + &screen_buffer, + &camera, + &image, + &scene, + &preview_render_data, None, + Some(preview_render_data.scale), ); } } }); s.spawn(|_| { - let result = Window::new( + window_res = Window::new( "racer-tracer", image.width, image.height, @@ -117,12 +105,12 @@ fn run(config: Config) -> Result<(), TracerError> { std::thread::sleep(std::time::Duration::from_millis(10)); if window.is_key_released(Key::R) { - if window_render_image.status() { - window_cancel_render.signal(); - window_render_image.reset(); + if render_image.status() { + cancel_render.signal(); + render_image.reset(); } else { - window_render_image.signal(); - window_cancel_render.reset(); + render_image.signal(); + cancel_render.reset(); } } @@ -150,19 +138,12 @@ fn run(config: Config) -> Result<(), TracerError> { .map_err(|e| TracerError::FailedToUpdateWindow(e.to_string())) })? } - window_exit.signal(); + exit.signal(); Ok(()) }); - - if result.is_err() { - let mut a = window_res.lock().expect("Failed to get result lock."); - *a = result; - } }); }); - - let res = (window_res.lock().expect("Failed to get result lock.")).clone(); - res + window_res } use structopt::StructOpt; fn main() { diff --git a/racer-tracer/src/render.rs b/racer-tracer/src/render.rs index 1d6d65d..8e01acb 100644 --- a/racer-tracer/src/render.rs +++ b/racer-tracer/src/render.rs @@ -1,8 +1,4 @@ -use std::{ - borrow::Borrow, - sync::{Arc, RwLock}, - time::Duration, -}; +use std::{borrow::Borrow, sync::RwLock, time::Duration}; use rayon::prelude::*; use synchronoise::SignalEvent; @@ -11,7 +7,7 @@ use crate::{ camera::Camera, config::RenderData, geometry::Hittable, - image::{QuadSplit, SubImage}, + image::{Image, SubImage}, ray::Ray, util::random_double, vec3::{Color, Vec3}, @@ -37,50 +33,27 @@ fn ray_color(scene: &dyn Hittable, ray: &Ray, depth: usize) -> Vec3 { (1.0 - t) * first_color + t * second_color } -pub fn raytrace( +pub fn raytrace_scaled( buffer: &RwLock<Vec<u32>>, - cancel_event: Option<Arc<SignalEvent>>, + cancel_event: Option<&SignalEvent>, scene: &dyn Hittable, - camera: &Camera, + camera: Camera, image: &SubImage, data: &RenderData, + scale: (usize, usize), ) { - // TODO: This scale shit doesn't work. - // Just force power of two or other solutions to avoid this. - // Can be ok for preview but the actual render could use a different function. - - let mut scaled_width = image.width / data.scale; - let mut scaled_height = image.height / data.scale; - // In the case where we get an odd one out we patch the widht and - // height with the esception of the edges of the screen. Without - // this everything has to be power of 2 which isn't a crazy - // asumption. - // - // Biggest problem is that the width and height we get here is - // depending on resolution and how many times the image is split - // up between threads. - if scaled_width * data.scale != image.width - && (image.x + scaled_width * data.scale + 1 < image.screen_width) - { - scaled_width += 1; - } + let (scale_width, scale_height) = scale; + let scaled_width = image.width / scale_width; + let scaled_height = image.height / scale_height; - if scaled_height * data.scale != image.height - && (image.y + scaled_height * data.scale + 1 < image.screen_height) - { - scaled_height += 1; - } - - let scaled_screen_width = image.screen_width / data.scale; - let scaled_screen_height = image.screen_height / data.scale; let mut colors: Vec<Vec3> = vec![Vec3::default(); scaled_height * scaled_width]; for row in 0..scaled_height { for column in 0..scaled_width { - let u: f64 = ((image.x / data.scale + column) as f64 + random_double()) - / (scaled_screen_width - 1) as f64; + let u: f64 = ((image.x + column * scale_width) as f64 + random_double()) + / (image.screen_width - 1) as f64; for _ in 0..data.samples { - let v: f64 = ((image.y / data.scale + row) as f64 + random_double()) - / (scaled_screen_height - 1) as f64; + let v: f64 = ((image.y + row * scale_height) as f64 + random_double()) + / (image.screen_height - 1) as f64; colors[row * scaled_width + column].add(ray_color( scene, &camera.get_ray(u, v), @@ -89,12 +62,12 @@ pub fn raytrace( } } - if do_cancel(&cancel_event) { + if do_cancel(cancel_event) { return; } } - if do_cancel(&cancel_event) { + if do_cancel(cancel_event) { return; } @@ -103,61 +76,157 @@ pub fn raytrace( .expect("Failed to get write guard when flushing data."); let offset = image.y * image.screen_width + image.x; - for half_row in 0..scaled_height { - for half_col in 0..scaled_width { - let color = colors[half_row * scaled_width + half_col] + for scaled_row in 0..scaled_height { + for scaled_col in 0..scaled_width { + let color = colors[scaled_row * scaled_width + scaled_col] .scale_sqrt(data.samples) .as_color(); - - let row = half_row * data.scale; - let col = half_col * data.scale; - - for scale_x in 0..data.scale { - for scale_y in 0..data.scale { - buf[offset + (row + scale_x) * image.screen_width + col + scale_y] = color; + let row = scaled_row * scale_height; + let col = scaled_col * scale_width; + for scale_h in 0..scale_height { + for scale_w in 0..scale_width { + buf[offset + (row + scale_h) * image.screen_width + col + scale_w] = color; } } } } } -fn do_cancel(cancel_event: &Option<Arc<SignalEvent>>) -> bool { +pub fn raytrace( + buffer: &RwLock<Vec<u32>>, + cancel_event: Option<&SignalEvent>, + scene: &dyn Hittable, + camera: Camera, + image: &SubImage, + data: &RenderData, +) { + let mut colors: Vec<Vec3> = vec![Vec3::default(); image.height * image.width]; + for row in 0..image.height { + for column in 0..image.width { + let u: f64 = + ((image.x + column) as f64 + random_double()) / (image.screen_width - 1) as f64; + for _ in 0..data.samples { + let v: f64 = + ((image.y + row) as f64 + random_double()) / (image.screen_height - 1) as f64; + colors[row * image.width + column].add(ray_color( + scene, + &camera.get_ray(u, v), + data.max_depth, + )); + } + } + + if do_cancel(cancel_event) { + return; + } + } + + if do_cancel(cancel_event) { + return; + } + + let mut buf = buffer + .write() + .expect("Failed to get write guard when flushing data."); + + let offset = image.y * image.screen_width + image.x; + for row in 0..image.height { + for col in 0..image.width { + let color = colors[row * image.width + col] + .scale_sqrt(data.samples) + .as_color(); + buf[offset + row * image.screen_width + col] = color; + } + } +} + +fn do_cancel(cancel_event: Option<&SignalEvent>) -> bool { match cancel_event { Some(event) => event.wait_timeout(Duration::from_secs(0)), None => false, } } +fn get_highest_divdable(value: usize, mut div: usize) -> usize { + // Feels like there could possibly be some other nicer trick to this. + while (value % div) != 0 { + div -= 1; + } + div +} + pub fn render( - buffer: Arc<RwLock<Vec<u32>>>, - camera: Arc<RwLock<Camera>>, - image: &SubImage, - scene: Arc<Box<dyn Hittable>>, - data: Arc<RenderData>, - split_depth: usize, - cancel_event: Option<Arc<SignalEvent>>, + buffer: &RwLock<Vec<u32>>, + camera: &RwLock<Camera>, + image: &Image, + scene: &dyn Hittable, + data: &RenderData, + cancel_event: Option<&SignalEvent>, + scale: Option<usize>, ) { - if do_cancel(&cancel_event) { + if do_cancel(cancel_event) { return; } - - if split_depth == 0 { - let scene: &(dyn Hittable) = (*scene).borrow(); - let camera = { camera.read().expect("TODO").clone() }; - raytrace(&buffer, cancel_event, scene, &camera, image, &data); - } else { - // Split into more quads - let quads = image.quad_split(); - quads.into_par_iter().for_each(|image| { - render( - Arc::clone(&buffer), - Arc::clone(&camera), - &image, - Arc::clone(&scene), - Arc::clone(&data), - split_depth - 1, - cancel_event.clone(), + let cam = camera.read().expect("TODO").clone(); + let width_step = image.width / data.num_threads_width; + let height_step = image.height / data.num_threads_height; + + let scaled_width = scale.map_or(1, |s| get_highest_divdable(width_step, s)); + let scaled_height = scale.map_or(1, |s| get_highest_divdable(height_step, s)); + + (0..data.num_threads_width) + .flat_map(|ws| { + let subs: Vec<SubImage> = (0..data.num_threads_height) + .map(|hs| SubImage { + x: width_step * ws, + y: height_step * hs, + screen_width: image.width, + screen_height: image.height, + + // Neccesary in case the threads width is not + // evenly divisible by the image width. + width: if ws == data.num_threads_width - 1 { + image.width - width_step * ws + } else { + width_step + }, + + // Neccesary in case the threads height is not + // evenly divisible by the image height. + height: if hs == data.num_threads_height - 1 { + image.height - height_step * hs + } else { + height_step + }, + }) + .collect(); + subs + }) + .collect::<Vec<SubImage>>() + .into_par_iter() + .for_each(|image| { + scale.map_or_else( + || { + raytrace( + buffer, + cancel_event, + (*scene).borrow(), + cam.clone(), + &image, + data, + ) + }, + |_| { + raytrace_scaled( + buffer, + cancel_event, + (*scene).borrow(), + cam.clone(), + &image, + data, + (scaled_width, scaled_height), + ) + }, ); }); - } } |
