Compare commits
2 Commits
b0dafe4739
...
235a9d1204
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
235a9d1204 | ||
|
|
1687077f4a |
@ -119,6 +119,9 @@ pub struct Opt {
|
|||||||
/// Image height
|
/// Image height
|
||||||
#[structopt(short = "h", long = "height", default_value = "1024")]
|
#[structopt(short = "h", long = "height", default_value = "1024")]
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
|
/// Number of threads
|
||||||
|
#[structopt(short = "t", long = "num_threads")]
|
||||||
|
pub num_threads: Option<usize>,
|
||||||
/// Sub-samples per pixel
|
/// Sub-samples per pixel
|
||||||
#[structopt(short = "s", long = "subsample", default_value = "8")]
|
#[structopt(short = "s", long = "subsample", default_value = "8")]
|
||||||
pub subsamples: usize,
|
pub subsamples: usize,
|
||||||
@ -139,6 +142,7 @@ pub struct Opt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn opt_hash(opt: &Opt) -> String {
|
pub fn opt_hash(opt: &Opt) -> String {
|
||||||
|
// TODO(wathiede): add threads.
|
||||||
format!(
|
format!(
|
||||||
"w:{}-h:{}-s:{}-pprof:{}-model:{}-use_accel:{}-{}",
|
"w:{}-h:{}-s:{}-pprof:{}-model:{}-use_accel:{}-{}",
|
||||||
opt.width,
|
opt.width,
|
||||||
@ -155,6 +159,7 @@ pub struct Scene {
|
|||||||
pub world: Box<Hit>,
|
pub world: Box<Hit>,
|
||||||
pub camera: Camera,
|
pub camera: Camera,
|
||||||
pub subsamples: usize,
|
pub subsamples: usize,
|
||||||
|
pub num_threads: Option<usize>,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
pub global_illumination: bool,
|
pub global_illumination: bool,
|
||||||
@ -236,6 +241,16 @@ enum Response {
|
|||||||
pixels: Vec<Vec3>,
|
pixels: Vec<Vec3>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
fn render_pixel(scene: &Scene, x: usize, y: usize) -> Vec3 {
|
||||||
|
let mut pixel: Vec3 = Default::default();
|
||||||
|
for _ in 0..scene.subsamples {
|
||||||
|
pixel = pixel + trace_pixel(x, y, scene);
|
||||||
|
}
|
||||||
|
pixel = pixel / scene.subsamples as f32;
|
||||||
|
// Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 or
|
||||||
|
// sqrt.
|
||||||
|
Vec3::new(pixel[0].sqrt(), pixel[1].sqrt(), pixel[2].sqrt())
|
||||||
|
}
|
||||||
|
|
||||||
fn render_worker(
|
fn render_worker(
|
||||||
tid: usize,
|
tid: usize,
|
||||||
@ -245,32 +260,27 @@ fn render_worker(
|
|||||||
) {
|
) {
|
||||||
for req in input_chan {
|
for req in input_chan {
|
||||||
match req {
|
match req {
|
||||||
|
Request::Line { width, y } => {
|
||||||
|
let pixels = (0..width).map(|x| render_pixel(scene, x, y)).collect();
|
||||||
|
output_chan.send(Response::Line { width, y, pixels });
|
||||||
|
}
|
||||||
Request::Pixel { x, y } => {
|
Request::Pixel { x, y } => {
|
||||||
let mut pixel: Vec3 = Default::default();
|
let pixel = render_pixel(scene, x, y);
|
||||||
for _ in 0..scene.subsamples {
|
|
||||||
pixel = pixel + trace_pixel(x, y, scene);
|
|
||||||
}
|
|
||||||
pixel = pixel / scene.subsamples as f32;
|
|
||||||
// Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 or
|
|
||||||
// sqrt.
|
|
||||||
let pixel = Vec3::new(pixel[0].sqrt(), pixel[1].sqrt(), pixel[2].sqrt());
|
|
||||||
|
|
||||||
output_chan.send(Response::Pixel { x, y, pixel });
|
output_chan.send(Response::Pixel { x, y, pixel });
|
||||||
}
|
}
|
||||||
_ => unimplemented!("Only Pixel requests are implemented"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trace!(target: "renderer", "Shutting down worker {}", tid);
|
trace!(target: "renderer", "Shutting down worker {}", tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::io::Error> {
|
pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::io::Error> {
|
||||||
let cpus = num_cpus::get();
|
let num_threads = scene.num_threads.unwrap_or_else(num_cpus::get);
|
||||||
let (pixel_req_tx, pixel_req_rx) = channel::bounded(2 * cpus);
|
let (pixel_req_tx, pixel_req_rx) = channel::bounded(2 * num_threads);
|
||||||
let (pixel_resp_tx, pixel_resp_rx) = channel::bounded(2 * cpus);
|
let (pixel_resp_tx, pixel_resp_rx) = channel::bounded(2 * num_threads);
|
||||||
|
|
||||||
let scene = sync::Arc::new(scene);
|
let scene = sync::Arc::new(scene);
|
||||||
println!("Creating {} render threads", cpus);
|
println!("Creating {} render threads", num_threads);
|
||||||
for i in 0..cpus {
|
for i in 0..num_threads {
|
||||||
let s = sync::Arc::clone(&scene);
|
let s = sync::Arc::clone(&scene);
|
||||||
let pixel_req_rx = pixel_req_rx.clone();
|
let pixel_req_rx = pixel_req_rx.clone();
|
||||||
let pixel_resp_tx = pixel_resp_tx.clone();
|
let pixel_resp_tx = pixel_resp_tx.clone();
|
||||||
@ -283,10 +293,16 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i
|
|||||||
|
|
||||||
let (w, h) = (scene.width, scene.height);
|
let (w, h) = (scene.width, scene.height);
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
// TODO(wathiede): handle sending Line requests for optimization.
|
let batch_by_line = true;
|
||||||
for y in 0..w {
|
if batch_by_line {
|
||||||
for x in 0..h {
|
for y in 0..h {
|
||||||
pixel_req_tx.send(Request::Pixel { x, y });
|
pixel_req_tx.send(Request::Line { width: w, y });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for y in 0..h {
|
||||||
|
for x in 0..w {
|
||||||
|
pixel_req_tx.send(Request::Pixel { x, y });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(pixel_req_tx);
|
drop(pixel_req_tx);
|
||||||
@ -295,8 +311,9 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i
|
|||||||
println!("Rendering with {} subsamples", scene.subsamples);
|
println!("Rendering with {} subsamples", scene.subsamples);
|
||||||
let mut img = RgbImage::new(scene.width as u32, scene.height as u32);
|
let mut img = RgbImage::new(scene.width as u32, scene.height as u32);
|
||||||
let total = scene.width * scene.height;
|
let total = scene.width * scene.height;
|
||||||
|
let mut cur_pixel = 0;
|
||||||
let mut last_progress = 1000;
|
let mut last_progress = 1000;
|
||||||
for (i, resp) in pixel_resp_rx.iter().enumerate() {
|
for resp in pixel_resp_rx {
|
||||||
match resp {
|
match resp {
|
||||||
Response::Pixel { x, y, pixel } => {
|
Response::Pixel { x, y, pixel } => {
|
||||||
let y_inv = scene.height - y - 1;
|
let y_inv = scene.height - y - 1;
|
||||||
@ -309,7 +326,7 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i
|
|||||||
(pixel[2] * 255.).min(255.) as u8,
|
(pixel[2] * 255.).min(255.) as u8,
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
let progress = 100 * i / total;
|
let progress = 100 * cur_pixel / total;
|
||||||
if progress != last_progress {
|
if progress != last_progress {
|
||||||
last_progress = progress;
|
last_progress = progress;
|
||||||
if progress % 10 == 0 {
|
if progress % 10 == 0 {
|
||||||
@ -319,8 +336,37 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i
|
|||||||
}
|
}
|
||||||
io::stdout().flush().unwrap();
|
io::stdout().flush().unwrap();
|
||||||
}
|
}
|
||||||
|
cur_pixel += 1;
|
||||||
|
}
|
||||||
|
Response::Line {
|
||||||
|
width: _,
|
||||||
|
y,
|
||||||
|
pixels,
|
||||||
|
} => {
|
||||||
|
for (x, pixel) in pixels.iter().enumerate() {
|
||||||
|
let y_inv = scene.height - y - 1;
|
||||||
|
img.put_pixel(
|
||||||
|
x as u32,
|
||||||
|
y_inv as u32,
|
||||||
|
image::Rgb([
|
||||||
|
(pixel[0] * 255.).min(255.) as u8,
|
||||||
|
(pixel[1] * 255.).min(255.) as u8,
|
||||||
|
(pixel[2] * 255.).min(255.) as u8,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
let progress = 100 * cur_pixel / total;
|
||||||
|
if progress != last_progress {
|
||||||
|
last_progress = progress;
|
||||||
|
if progress % 10 == 0 {
|
||||||
|
print!("{}%", progress);
|
||||||
|
} else {
|
||||||
|
print!(".");
|
||||||
|
}
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
}
|
||||||
|
cur_pixel += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => unimplemented!("Only Pixel responses are implemented"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
|||||||
@ -69,6 +69,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
|||||||
@ -51,6 +51,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
|||||||
@ -63,6 +63,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
|||||||
@ -130,6 +130,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
|||||||
@ -115,6 +115,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
|||||||
@ -166,6 +166,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world: Box::new(HitableList::new(list)),
|
world: Box::new(HitableList::new(list)),
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
|||||||
@ -144,6 +144,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
|||||||
@ -65,6 +65,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
|||||||
@ -142,6 +142,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
|||||||
@ -70,6 +70,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
subsamples: opt.subsamples,
|
subsamples: opt.subsamples,
|
||||||
|
num_threads: opt.num_threads,
|
||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user