Implemented basic multi-threaded rendering.
It's a bit inefficient because a thread is spawned for each pixel. Need to implement bucketing.
This commit is contained in:
parent
fac46d6db3
commit
a681ba461e
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -4,7 +4,9 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -52,6 +54,14 @@ name = "nom"
|
|||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.71"
|
||||
|
@ -74,6 +84,11 @@ name = "rustc-serialize"
|
|||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scoped_threadpool"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.3.0"
|
||||
|
|
|
@ -7,3 +7,5 @@ authors = ["Nathan Vegdahl <cessen@cessen.com>"]
|
|||
docopt = "0.6"
|
||||
rustc-serialize = "0.3"
|
||||
nom = "1.2"
|
||||
scoped_threadpool = "0.1"
|
||||
num_cpus = "0.2"
|
|
@ -1,6 +1,6 @@
|
|||
Scene $Scene_fr1 {
|
||||
Output {
|
||||
Path ["cube.ppm"]
|
||||
Path ["test_renders/cube.ppm"]
|
||||
}
|
||||
RenderSettings {
|
||||
Resolution [960 540]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
extern crate rustc_serialize;
|
||||
extern crate docopt;
|
||||
extern crate scoped_threadpool;
|
||||
extern crate num_cpus;
|
||||
#[macro_use]
|
||||
extern crate nom;
|
||||
|
||||
|
@ -99,7 +101,7 @@ fn main() {
|
|||
}
|
||||
|
||||
println!("Rendering scene...");
|
||||
r.render();
|
||||
r.render(num_cpus::get() as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -606,8 +606,7 @@ mod tests {
|
|||
let (token8, input9) = next_token(input8);
|
||||
|
||||
assert_eq!((token1, input2),
|
||||
(Token::TypeName("Thing"),
|
||||
(5, " $yar { # A comment\n\tThing2 []\n}")));
|
||||
(Token::TypeName("Thing"), (5, " $yar { # A comment\n\tThing2 []\n}")));
|
||||
assert_eq!((token2, input3),
|
||||
(Token::Ident("$yar"), (10, " { # A comment\n\tThing2 []\n}")));
|
||||
assert_eq!((token3, input4),
|
||||
|
|
|
@ -52,9 +52,7 @@ pub fn parse_scene(tree: &DataTree) -> Result<Renderer, PsyParseError> {
|
|||
.unwrap()));
|
||||
|
||||
// Parse render settings
|
||||
let render_settings = try!(parse_render_settings(tree.iter_children_with_type("Rende\
|
||||
rSett\
|
||||
ings")
|
||||
let render_settings = try!(parse_render_settings(tree.iter_children_with_type("RenderSettings")
|
||||
.nth(0)
|
||||
.unwrap()));
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::Mutex;
|
||||
use std::cell::RefCell;
|
||||
use scoped_threadpool::Pool;
|
||||
|
||||
use tracer::Tracer;
|
||||
use halton;
|
||||
|
@ -18,10 +21,11 @@ pub struct Renderer {
|
|||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn render(&self) {
|
||||
let mut rays = Vec::new();
|
||||
let mut tracer = Tracer::from_assembly(&self.scene.root);
|
||||
let mut img = Image::new(self.resolution.0, self.resolution.1);
|
||||
pub fn render(&self, thread_count: u32) {
|
||||
let mut tpool = Pool::new(thread_count);
|
||||
|
||||
let img = Mutex::new(RefCell::new(Image::new(self.resolution.0, self.resolution.1)));
|
||||
|
||||
|
||||
// Pre-calculate some useful values related to the image plane
|
||||
let cmpx = 1.0 / self.resolution.0 as f32;
|
||||
|
@ -35,24 +39,41 @@ impl Renderer {
|
|||
|
||||
|
||||
// Render
|
||||
for y in 0..img.height() {
|
||||
for x in 0..img.width() {
|
||||
tpool.scoped(|scope| {
|
||||
let (img_width, img_height) = {
|
||||
let i = img.lock().unwrap();
|
||||
let w = i.borrow().width();
|
||||
let h = i.borrow().height();
|
||||
(w, h)
|
||||
};
|
||||
for y in 0..img_height {
|
||||
for x in 0..img_width {
|
||||
let img = &img;
|
||||
scope.execute(move || {
|
||||
let mut rays = Vec::new();
|
||||
let mut tracer = Tracer::from_assembly(&self.scene.root);
|
||||
|
||||
let offset = hash_u32(((x as u32) << 16) ^ (y as u32), 0);
|
||||
|
||||
// Generate rays
|
||||
rays.clear();
|
||||
for si in 0..self.spp {
|
||||
let mut ray = {
|
||||
let filter_x = fast_logit(halton::sample(3, offset + si as u32), 1.5) + 0.5;
|
||||
let filter_y = fast_logit(halton::sample(4, offset + si as u32), 1.5) + 0.5;
|
||||
let filter_x =
|
||||
fast_logit(halton::sample(3, offset + si as u32), 1.5) + 0.5;
|
||||
let filter_y =
|
||||
fast_logit(halton::sample(4, offset + si as u32), 1.5) + 0.5;
|
||||
let samp_x = (filter_x + x as f32) * cmpx;
|
||||
let samp_y = (filter_y + y as f32) * cmpy;
|
||||
|
||||
self.scene.camera.generate_ray((samp_x - 0.5) * x_extent,
|
||||
(0.5 - samp_y) * y_extent,
|
||||
halton::sample(0, offset + si as u32),
|
||||
halton::sample(1, offset + si as u32),
|
||||
halton::sample(2, offset + si as u32))
|
||||
halton::sample(0,
|
||||
offset + si as u32),
|
||||
halton::sample(1,
|
||||
offset + si as u32),
|
||||
halton::sample(2,
|
||||
offset + si as u32))
|
||||
};
|
||||
ray.id = si as u32;
|
||||
rays.push(ray);
|
||||
|
@ -85,12 +106,21 @@ impl Renderer {
|
|||
b = 255.0 * srgb_gamma(b / self.spp as f32);
|
||||
|
||||
// Set pixel color
|
||||
img.set(x, y, (r as u8, g as u8, b as u8));
|
||||
let img = img.lock().unwrap();
|
||||
img.borrow_mut().set(x, y, (r as u8, g as u8, b as u8));
|
||||
});
|
||||
}
|
||||
}
|
||||
// scope.defer(|| println!("Exiting scope"));
|
||||
// scope.spawn(|| println!("Running child thread in scope"))
|
||||
});
|
||||
|
||||
|
||||
// Write rendered image to disk
|
||||
let _ = img.write_binary_ppm(Path::new(&self.output_file));
|
||||
{
|
||||
let img = &img.lock().unwrap();
|
||||
let _ = img.borrow().write_binary_ppm(Path::new(&self.output_file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,6 @@ pub enum SurfaceIntersection {
|
|||
},
|
||||
}
|
||||
|
||||
pub trait Surface: Boundable + Debug {
|
||||
pub trait Surface: Boundable + Debug + Sync {
|
||||
fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user