summaryrefslogtreecommitdiff
path: root/racer-tracer
diff options
context:
space:
mode:
Diffstat (limited to 'racer-tracer')
-rw-r--r--racer-tracer/config.yml12
-rw-r--r--racer-tracer/src/config.rs3
-rw-r--r--racer-tracer/src/image.rs65
-rw-r--r--racer-tracer/src/main.rs89
-rw-r--r--racer-tracer/src/render.rs227
5 files changed, 193 insertions, 203 deletions
diff --git a/racer-tracer/config.yml b/racer-tracer/config.yml
index f32f991..66af4a6 100644
--- a/racer-tracer/config.yml
+++ b/racer-tracer/config.yml
@@ -1,14 +1,16 @@
preview:
samples: 2
max_depth: 4
- recurse_depth: 4
- scale: 4
+ scale: 2
+ num_threads_width: 10
+ num_threads_height: 10
render:
- samples: 1000
- max_depth: 40
- recurse_depth: 4
+ samples: 100
+ max_depth: 20
scale: 1
+ num_threads_width: 10
+ num_threads_height: 10
screen:
width: 1280
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),
+ )
+ },
);
});
- }
}