summaryrefslogtreecommitdiff
path: root/racer-tracer
diff options
context:
space:
mode:
authorSakarias Johansson <sakarias.johansson@goodbyekansas.com>2023-03-03 15:56:26 +0100
committerSakarias Johansson <sakariasjohansson@hotmail.com>2023-03-03 20:12:05 +0100
commit548011ba6316e83c95b327768581d7d53d49a63e (patch)
tree3307873a1337f5688eb29e514c04fe0ed6345a97 /racer-tracer
parent971372cf6350533e36db0404afedb1a36817037c (diff)
downloadracer-tracer-548011ba6316e83c95b327768581d7d53d49a63e.tar.gz
racer-tracer-548011ba6316e83c95b327768581d7d53d49a63e.tar.xz
racer-tracer-548011ba6316e83c95b327768581d7d53d49a63e.zip
🛠 Cleanup error handling & functionalize
Diffstat (limited to 'racer-tracer')
-rw-r--r--racer-tracer/src/error.rs14
-rw-r--r--racer-tracer/src/main.rs127
-rw-r--r--racer-tracer/src/render.rs220
3 files changed, 209 insertions, 152 deletions
diff --git a/racer-tracer/src/error.rs b/racer-tracer/src/error.rs
index f32dac9..6e1b305 100644
--- a/racer-tracer/src/error.rs
+++ b/racer-tracer/src/error.rs
@@ -1,6 +1,6 @@
use thiserror::Error;
-#[derive(Clone, Error, Debug)]
+#[derive(Clone, Error, Debug, PartialEq, Eq)]
pub enum TracerError {
#[error("Unknown error: {message}")]
Unknown { message: String, exit_code: i32 },
@@ -22,6 +22,15 @@ pub enum TracerError {
#[error("No scene supplied.")]
NoScene(),
+
+ #[error("Failed to acquire lock \"{0}\"")]
+ FailedToAcquireLock(String),
+
+ #[error("Exit event")]
+ ExitEvent,
+
+ #[error("Cancel event")]
+ CancelEvent,
}
impl From<TracerError> for i32 {
@@ -37,6 +46,9 @@ impl From<TracerError> for i32 {
TracerError::Configuration(_, _) => 5,
TracerError::UnknownMaterial(_) => 6,
TracerError::NoScene() => 7,
+ TracerError::FailedToAcquireLock(_) => 8,
+ TracerError::ExitEvent => 9,
+ TracerError::CancelEvent => 10,
}
}
}
diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs
index b441dd0..7d7510f 100644
--- a/racer-tracer/src/main.rs
+++ b/racer-tracer/src/main.rs
@@ -30,18 +30,16 @@ use crate::{
};
fn run(config: Config) -> Result<(), TracerError> {
- let preview_render_data = config.preview;
- let render_data = config.render;
let image = image::Image::new(config.screen.width, config.screen.height);
+ let screen_buffer: RwLock<Vec<u32>> = 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 mut window_res: Result<(), TracerError> = Ok(());
- let move_camera = &camera;
+ let mut render_res: Result<(), TracerError> = Ok(());
let render_image = SignalEvent::manual(false);
let cancel_render = SignalEvent::manual(false);
@@ -49,41 +47,54 @@ fn run(config: Config) -> Result<(), TracerError> {
rayon::scope(|s| {
s.spawn(|_| {
- loop {
- if exit.wait_timeout(Duration::from_secs(0)) {
- return;
- }
+ while render_res.is_ok() {
+ render_res = (!exit.wait_timeout(Duration::from_secs(0)))
+ .then_some(|| ())
+ .ok_or(TracerError::ExitEvent)
+ .and_then(|_| {
+ render_image
+ .wait_timeout(Duration::from_secs(0))
+ .then_some(|| ())
+ .map_or_else(
+ || {
+ // Render preview
+ render(
+ &screen_buffer,
+ &camera,
+ &image,
+ &scene,
+ &config.preview,
+ None,
+ Some(config.preview.scale),
+ )
+ },
+ |_| {
+ let render_time = Instant::now();
+ let res = render(
+ &screen_buffer,
+ &camera,
+ &image,
+ &scene,
+ &config.render,
+ Some(&cancel_render),
+ None,
+ );
+ render_image.reset();
- if render_image.wait_timeout(Duration::from_secs(0)) && render_image.status() {
- let render_time = Instant::now();
- render(
- &screen_buffer,
- &camera,
- &image,
- &scene,
- &render_data,
- Some(&cancel_render),
- None,
- );
-
- println!(
- "It took {} seconds to render the image.",
- Instant::now().duration_since(render_time).as_millis()
- );
- } else {
- // Render preview
- render(
- &screen_buffer,
- &camera,
- &image,
- &scene,
- &preview_render_data,
- None,
- Some(preview_render_data.scale),
- );
- }
+ println!(
+ "It took {} seconds to render the image.",
+ Instant::now().duration_since(render_time).as_secs()
+ );
+
+ // TODO: Output the image
+
+ res
+ },
+ )
+ });
}
});
+
s.spawn(|_| {
window_res = Window::new(
"racer-tracer",
@@ -106,28 +117,32 @@ fn run(config: Config) -> Result<(), TracerError> {
if window.is_key_released(Key::R) {
if render_image.status() {
+ // Signal cancel
cancel_render.signal();
render_image.reset();
} else {
+ // Signal render
render_image.signal();
cancel_render.reset();
}
}
- {
- let mut cam = move_camera.write().expect("TODO");
- if window.is_key_down(Key::W) {
- cam.go_forward(-dt);
- } else if window.is_key_down(Key::S) {
- cam.go_forward(dt);
- }
+ camera
+ .write()
+ .map_err(|e| TracerError::FailedToAcquireLock(e.to_string()))
+ .map(|mut cam| {
+ if window.is_key_down(Key::W) {
+ cam.go_forward(-dt);
+ } else if window.is_key_down(Key::S) {
+ cam.go_forward(dt);
+ }
- if window.is_key_down(Key::A) {
- cam.go_right(-dt);
- } else if window.is_key_down(Key::D) {
- cam.go_right(dt);
- }
- }
+ if window.is_key_down(Key::A) {
+ cam.go_right(-dt);
+ } else if window.is_key_down(Key::D) {
+ cam.go_right(dt);
+ }
+ })?;
screen_buffer
.read()
@@ -139,16 +154,22 @@ fn run(config: Config) -> Result<(), TracerError> {
})?
}
exit.signal();
+ cancel_render.signal();
Ok(())
});
});
});
- window_res
+
+ window_res.and(render_res)
}
use structopt::StructOpt;
fn main() {
- if let Err(e) = Config::try_from(Args::from_args()).and_then(run) {
- eprintln!("{}", e);
- std::process::exit(e.into())
+ match Config::try_from(Args::from_args()).and_then(run) {
+ Err(TracerError::ExitEvent) => {}
+ Ok(_) => {}
+ Err(e) => {
+ eprintln!("{}", e);
+ std::process::exit(e.into())
+ }
}
}
diff --git a/racer-tracer/src/render.rs b/racer-tracer/src/render.rs
index 8e01acb..fefafce 100644
--- a/racer-tracer/src/render.rs
+++ b/racer-tracer/src/render.rs
@@ -6,6 +6,7 @@ use synchronoise::SignalEvent;
use crate::{
camera::Camera,
config::RenderData,
+ error::TracerError,
geometry::Hittable,
image::{Image, SubImage},
ray::Ray,
@@ -41,7 +42,7 @@ pub fn raytrace_scaled(
image: &SubImage,
data: &RenderData,
scale: (usize, usize),
-) {
+) -> Result<(), TracerError> {
let (scale_width, scale_height) = scale;
let scaled_width = image.width / scale_width;
let scaled_height = image.height / scale_height;
@@ -63,33 +64,36 @@ pub fn raytrace_scaled(
}
if do_cancel(cancel_event) {
- return;
+ return Ok(());
}
}
- 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 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 = 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;
+ (!do_cancel(cancel_event))
+ .then_some(|| ())
+ .ok_or(TracerError::CancelEvent)
+ .and_then(|_| {
+ buffer
+ .write()
+ .map_err(|e| TracerError::FailedToAcquireLock(e.to_string()))
+ })
+ .map(|mut buf| {
+ let offset = image.y * image.screen_width + image.x;
+ 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 = 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;
+ }
+ }
}
}
- }
- }
+ })
}
pub fn raytrace(
@@ -99,7 +103,7 @@ pub fn raytrace(
camera: Camera,
image: &SubImage,
data: &RenderData,
-) {
+) -> Result<(), TracerError> {
let mut colors: Vec<Vec3> = vec![Vec3::default(); image.height * image.width];
for row in 0..image.height {
for column in 0..image.width {
@@ -117,27 +121,29 @@ pub fn raytrace(
}
if do_cancel(cancel_event) {
- return;
+ return Ok(());
}
}
- 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;
- }
- }
+ (!do_cancel(cancel_event))
+ .then_some(|| ())
+ .ok_or(TracerError::CancelEvent)
+ .and_then(|_| {
+ buffer
+ .write()
+ .map_err(|e| TracerError::FailedToAcquireLock(e.to_string()))
+ })
+ .map(|mut buf| {
+ 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 {
@@ -163,70 +169,88 @@ pub fn render(
data: &RenderData,
cancel_event: Option<&SignalEvent>,
scale: Option<usize>,
-) {
+) -> Result<(), TracerError> {
if do_cancel(cancel_event) {
- return;
+ return Ok(());
}
- 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
- },
+ (!do_cancel(cancel_event))
+ .then_some(|| ())
+ .ok_or(TracerError::CancelEvent)
+ .and_then(|_| {
+ camera
+ .read()
+ .map_err(|e| TracerError::FailedToAcquireLock(e.to_string()))
+ // We make a clone of it as it's not very important to
+ // have the latest camera angle etc. Better to keep
+ // the lock to a minimum.
+ .map(|cam| cam.clone())
+ })
+ .map(|cam| {
+ let images = (0..data.num_threads_width)
+ .flat_map(|ws| {
+ (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::<Vec<SubImage>>()
})
- .collect();
- subs
+ .collect::<Vec<SubImage>>();
+
+ (cam, images)
})
- .collect::<Vec<SubImage>>()
- .into_par_iter()
- .for_each(|image| {
- scale.map_or_else(
- || {
- raytrace(
- buffer,
- cancel_event,
- (*scene).borrow(),
- cam.clone(),
- &image,
- data,
+ .and_then(|(cam, sub_images)| {
+ sub_images
+ .into_par_iter()
+ .map(|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),
+ )
+ },
)
- },
- |_| {
- raytrace_scaled(
- buffer,
- cancel_event,
- (*scene).borrow(),
- cam.clone(),
- &image,
- data,
- (scaled_width, scaled_height),
- )
- },
- );
- });
+ })
+ .collect::<Result<(), TracerError>>()
+ })
}