Implement multithreading

This commit is contained in:
Max Nuding 2022-07-02 18:17:03 +02:00
parent 2903c9b0b9
commit 4b8b556ea3
Signed by: phlaym
GPG Key ID: 0AAD39863E09DC48
4 changed files with 164 additions and 25 deletions

122
Cargo.lock generated
View File

@ -2,12 +2,69 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-channel"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "either"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.7" version = "0.2.7"
@ -19,12 +76,46 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.126" version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.16" version = "0.2.16"
@ -61,13 +152,44 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "rayon"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]] [[package]]
name = "rustracer" name = "rustracer"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"rand", "rand",
"rayon",
] ]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"

View File

@ -7,3 +7,4 @@ edition = "2021"
[dependencies] [dependencies]
rand = "0.8.5" rand = "0.8.5"
rayon = "1.5.3"

View File

@ -1,9 +1,13 @@
use std::sync::Mutex;
use std::time::Instant;
use crate::camera::Camera; use crate::camera::Camera;
use crate::hittable::{Hittable, Sphere}; use crate::hittable::{Hittable, Sphere};
use crate::output::{Output, P3}; use crate::output::{Output, P3};
use crate::ray::Ray; use crate::ray::Ray;
use crate::vec3::{Color, Point3, Vec3}; use crate::vec3::{Color, Point3, Vec3};
use rand::distributions::{Distribution, Uniform}; use rand::distributions::{Distribution, Uniform};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use crate::material::{Dielectric, Lambertian, Material, Metal}; use crate::material::{Dielectric, Lambertian, Material, Metal};
mod vec3; mod vec3;
@ -13,8 +17,8 @@ mod material;
mod camera; mod camera;
mod output; mod output;
fn random_scene() -> Vec<Box<dyn Hittable>> { fn random_scene() -> Vec<Box<dyn Hittable + Sync>> {
let mut world:Vec<Box<dyn Hittable>> = Vec::new(); let mut world:Vec<Box<dyn Hittable + Sync>> = Vec::new();
let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5))); let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5)));
let ground = Sphere { let ground = Sphere {
@ -82,8 +86,9 @@ fn main() {
const ASPECT_RATIO: f64 = 3.0 / 2.0; const ASPECT_RATIO: f64 = 3.0 / 2.0;
const IMAGE_WIDTH: usize = 1200; const IMAGE_WIDTH: usize = 1200;
const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize; const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize;
const SAMPLES_PER_PIXEL: i32 = 100; const SAMPLES_PER_PIXEL: i32 = 500;
const MAX_DEPTH: i32 = 50; const MAX_DEPTH: i32 = 50;
let hh = IMAGE_HEIGHT;
let look_from = Point3::new(13.0, 2.0, 3.0); let look_from = Point3::new(13.0, 2.0, 3.0);
let look_at = Point3::new(0.0, 0.0, 0.0); let look_at = Point3::new(0.0, 0.0, 0.0);
@ -101,27 +106,38 @@ fn main() {
// World // World
let world= random_scene(); let world= random_scene();
//println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT);
let between = Uniform::from(0.0..1.0); let between = Uniform::from(0.0..1.0);
let mut pixels = Vec::<u8>::new();
let mut rng = rand::thread_rng();
for j in (0..IMAGE_HEIGHT).rev() {
eprint!("\rScanlines remaining: {} ", j);
for i in 0..IMAGE_WIDTH {
let mut color = Color::default();
(0..SAMPLES_PER_PIXEL).for_each(|_s| {
let random_number = between.sample(&mut rng);
let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
let ray = cam.get_ray(u, v);
color += ray.pixel_color(&world, MAX_DEPTH);
});
pixels.append(&mut color.into_bytes(SAMPLES_PER_PIXEL));
//color.write_color(SAMPLES_PER_PIXEL); let start = Instant::now();
let mut pixels = vec![0; IMAGE_WIDTH * IMAGE_HEIGHT * 3];
let bands: Vec<(usize, &mut [u8])> = pixels.chunks_mut(3).enumerate().collect();
let count = Mutex::new(0);
bands.into_par_iter().for_each(|(i, pixel)| {
let row = IMAGE_HEIGHT - (i / IMAGE_WIDTH) - 1;
let col = i % IMAGE_WIDTH;
let mut rng = rand::thread_rng();
let mut color = Color::default();
(0..SAMPLES_PER_PIXEL).for_each(|_s| {
let random_number = between.sample(&mut rng);
let u = (col as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
let v = (row as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
let ray = cam.get_ray(u, v);
color += ray.pixel_color(&world, MAX_DEPTH);
});
let bytes = color.into_bytes(SAMPLES_PER_PIXEL);
pixel[0] = bytes[0];
pixel[1] = bytes[1];
pixel[2] = bytes[2];
if i % 100 == 0 {
let mut rem = count.lock().unwrap();
let percent_done_before = 100 * *rem / (IMAGE_WIDTH * IMAGE_HEIGHT);
*rem += 100;
let percent_done_after = 100 * *rem / (IMAGE_WIDTH * IMAGE_HEIGHT);
if percent_done_before != percent_done_after {
eprint!("\rProgress: {}% ", percent_done_after);
}
} }
} });
P3::write("i.ppm", &pixels, IMAGE_WIDTH, IMAGE_HEIGHT).expect("Error writing image: {}"); P3::write("imc.ppm", &pixels, IMAGE_WIDTH, IMAGE_HEIGHT).expect("Error writing image: {}");
eprintln!("\nDone"); eprintln!("\nDone. Time: {}ms", start.elapsed().as_millis());
} }

View File

@ -23,7 +23,7 @@ impl Ray {
} }
pub fn direction(&self) -> Vec3 { self.direction } pub fn direction(&self) -> Vec3 { self.direction }
pub fn origin(&self) -> Point3 { self.origin } pub fn origin(&self) -> Point3 { self.origin }
pub fn pixel_color(&self, world: &Vec<Box<dyn Hittable>>, depth: i32) -> Color { pub fn pixel_color(&self, world: &Vec<Box<dyn Hittable + Sync>>, depth: i32) -> Color {
if depth <= 0 { if depth <= 0 {
return Color::default(); return Color::default();
} }
@ -50,7 +50,7 @@ impl Ray {
} }
fn hit_world<'material>( fn hit_world<'material>(
&self, &self,
world: &'material Vec<Box<dyn Hittable>>, world: &'material Vec<Box<dyn Hittable + Sync>>,
t_min: f64, t_min: f64,
t_max: f64, t_max: f64,
) -> Option<HitRecord<'material>> { ) -> Option<HitRecord<'material>> {