Render buckets in hilbert curve order.

Provides a slight speed-up.
This commit is contained in:
Nathan Vegdahl 2016-07-16 14:53:03 -07:00
parent 5bc97f69b8
commit ec75f11206
4 changed files with 123 additions and 15 deletions

87
src/hilbert.rs Normal file
View File

@ -0,0 +1,87 @@
#![allow(dead_code)]
const N: u32 = 1 << 16;
// Utility function used by the functions below.
fn hil_rot(n: u32, rx: u32, ry: u32, x: &mut u32, y: &mut u32) {
if ry == 0 {
if rx == 1 {
*x = (n - 1).wrapping_sub(*x);
*y = (n - 1).wrapping_sub(*y);
}
let t = *x;
*x = *y;
*y = t;
}
}
/// Convert (x,y) to hilbert curve index.
///
/// x: The x coordinate. Must be a positive integer no greater than 2^16-1.
/// y: The y coordinate. Must be a positive integer no greater than 2^16-1.
///
/// Returns the hilbert curve index corresponding to the (x,y) coordinates given.
pub fn xy2d(x: u32, y: u32) -> u32 {
assert!(x < N);
assert!(y < N);
let (mut x, mut y) = (x, y);
let mut d = 0;
let mut s = N >> 1;
while s > 0 {
let rx = if (x & s) > 0 {
1
} else {
0
};
let ry = if (y & s) > 0 {
1
} else {
0
};
d += s * s * ((3 * rx) ^ ry);
hil_rot(s, rx, ry, &mut x, &mut y);
s >>= 1
}
d
}
/// Convert hilbert curve index to (x,y).
///
/// d: The hilbert curve index.
///
/// Returns the (x, y) coords at the given index.
pub fn d2xy(d: u32) -> (u32, u32) {
let (mut x, mut y) = (0, 0);
let mut s = 1;
let mut t = d;
while s < N {
let rx = 1 & (t >> 1);
let ry = 1 & (t ^ rx);
hil_rot(s, rx, ry, &mut x, &mut y);
x += s * rx;
y += s * ry;
t >>= 2;
s <<= 1;
}
(x, y)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reversible() {
let d = 54;
let (x, y) = d2xy(d);
let d2 = xy2d(x, y);
assert_eq!(d, d2);
}
}

View File

@ -9,6 +9,7 @@ extern crate lodepng;
extern crate nom;
mod math;
mod hilbert;
mod algorithm;
mod lerp;
mod float4;

View File

@ -39,7 +39,18 @@ pub fn fast_ln(x: f32) -> f32 {
}
/// Rounds an integer up to the next power of two.
pub fn upper_power_of_two(mut v: u32) -> u32 {
v -= 1;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v + 1
}
/// Gets the log base 2 of the given integer
pub fn log2_64(value: u64) -> u64 {
const TAB64: [u64; 64] = [63, 0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, 51,
37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, 57, 46,

View File

@ -1,3 +1,4 @@
use std::cmp;
use std::io::{self, Write};
use std::path::Path;
use std::cmp::min;
@ -10,7 +11,8 @@ use algorithm::partition_pair;
use ray::Ray;
use tracer::Tracer;
use halton;
use math::fast_logit;
use hilbert;
use math::{fast_logit, upper_power_of_two};
use image::Image;
use surface;
use scene::Scene;
@ -184,20 +186,27 @@ impl Renderer {
};
// Populate job queue
for by in 0..((img_height / bucket_h) + 1) {
for bx in 0..((img_width / bucket_w) + 1) {
let x = bx * bucket_w;
let y = by * bucket_h;
let w = min(bucket_w, img_width - x);
let h = min(bucket_h, img_height - y);
if w > 0 && h > 0 {
job_queue.push(BucketJob {
x: x as u32,
y: y as u32,
w: w as u32,
h: h as u32,
});
}
let bucket_n = {
let bucket_count_x = ((img_width / bucket_w) + 1) as u32;
let bucket_count_y = ((img_height / bucket_h) + 1) as u32;
let larger = cmp::max(bucket_count_x, bucket_count_y);
let pow2 = upper_power_of_two(larger);
pow2 * pow2
};
for hilbert_d in 0..bucket_n {
let (bx, by) = hilbert::d2xy(hilbert_d);
let x = bx as usize * bucket_w;
let y = by as usize * bucket_h;
let w = min(bucket_w, img_width - x);
let h = min(bucket_h, img_height - y);
if x < img_width && y < img_height && w > 0 && h > 0 {
job_queue.push(BucketJob {
x: x as u32,
y: y as u32,
w: w as u32,
h: h as u32,
});
}
}