use super::{GBuffers, SIGMA_EPS};
use glam::Vec3;
use std::{
any::Any,
ops::Range,
panic::{AssertUnwindSafe, catch_unwind, resume_unwind},
sync::{
Condvar, Mutex, MutexGuard, PoisonError,
atomic::{AtomicU32, Ordering},
},
thread,
};
const B3_SPLINE: [f32; 5] = [1.0 / 16.0, 1.0 / 4.0, 3.0 / 8.0, 1.0 / 4.0, 1.0 / 16.0];
const BANDS_PER_THREAD: usize = 4;
#[inline]
const fn sanitize(v: f32) -> f32 {
if v.is_finite() { v } else { 0.0 }
}
#[inline]
const fn sanitize_vec3(v: Vec3) -> Vec3 {
Vec3::new(sanitize(v.x), sanitize(v.y), sanitize(v.z))
}
#[inline]
const fn facet_weight(a: i32, b: i32) -> f32 {
if a == b { 1.0 } else { 0.0 }
}
#[inline]
pub(super) fn unit_normal_or_zero(n: Vec3) -> Vec3 {
let n = sanitize_vec3(n);
let len = n.length();
if len <= SIGMA_EPS {
Vec3::ZERO
} else {
n / len
}
}
#[inline]
pub(super) fn cos_pow(base: f32, power: f32) -> f32 {
if power >= 0.0 && power.fract() == 0.0 && power <= u32::MAX as f32 {
#[expect(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
reason = "power is a non-negative whole number no larger than u32::MAX, checked just above"
)]
let int_power = power as u32;
if int_power.is_power_of_two() {
let squarings = int_power.trailing_zeros();
let mut v = base;
for _ in 0..squarings {
v *= v;
}
return v;
}
}
base.powf(power)
}
#[inline]
fn normal_weight_unit(a_n: Vec3, b_n: Vec3, power: f32) -> f32 {
if a_n == Vec3::ZERO || b_n == Vec3::ZERO {
return 1.0;
}
let cos_theta = a_n.dot(b_n).clamp(-1.0, 1.0).max(0.0);
cos_pow(cos_theta, power.max(0.0))
}
#[inline]
fn depth_weight(a: f32, b: f32, neg_inv_sigma_depth: f32) -> f32 {
let gap = (sanitize(a) - sanitize(b)).abs();
if gap == 0.0 {
1.0
} else {
(gap * neg_inv_sigma_depth).exp()
}
}
#[inline]
fn color_weight(a: Vec3, b: Vec3, neg_inv_two_sigma_sq: f32) -> f32 {
let dist_sq = (a - b).length_squared();
if dist_sq == 0.0 {
1.0
} else {
(dist_sq * neg_inv_two_sigma_sq).exp()
}
}
pub(super) struct TapConstants<'a> {
pub(super) normal_n: &'a [Vec3],
pub(super) neg_inv_sigma_depth: f32,
pub(super) neg_inv_two_sigma_color_sq: f32,
pub(super) normal_power: f32,
}
#[derive(Default)]
pub(super) struct SharedColors {
texels: Vec<[AtomicU32; 3]>,
}
impl SharedColors {
pub(super) const fn new() -> Self {
Self { texels: Vec::new() }
}
pub(super) fn resize(&mut self, len: usize) {
if self.texels.len() != len {
self.texels.clear();
self.texels.resize_with(len, Default::default);
}
}
#[inline]
fn load(&self, idx: usize) -> Vec3 {
let [x, y, z] = &self.texels[idx];
Vec3::new(
f32::from_bits(x.load(Ordering::Relaxed)),
f32::from_bits(y.load(Ordering::Relaxed)),
f32::from_bits(z.load(Ordering::Relaxed)),
)
}
#[inline]
fn store(&self, idx: usize, value: Vec3) {
let [x, y, z] = &self.texels[idx];
x.store(value.x.to_bits(), Ordering::Relaxed);
y.store(value.y.to_bits(), Ordering::Relaxed);
z.store(value.z.to_bits(), Ordering::Relaxed);
}
pub(super) fn fill_from(&self, source: &[Vec3]) {
for (idx, &value) in source.iter().enumerate().take(self.texels.len()) {
self.store(idx, value);
}
}
pub(super) fn copy_to(&self, dest: &mut [Vec3]) {
let shared = self.texels.len();
for (idx, out) in dest.iter_mut().enumerate().take(shared) {
*out = self.load(idx);
}
}
}
struct Centre {
facet: i32,
sig: u32,
depth: f32,
normal: Vec3,
color: Vec3,
}
#[inline]
fn shifted(base: usize, offset: i64, limit: usize) -> Option<usize> {
i64::try_from(base)
.ok()
.and_then(|base| usize::try_from(base + offset).ok())
.filter(|&pos| pos < limit)
}
#[inline]
fn tap_contribution(
centre: &Centre,
g: &GBuffers<'_>,
tap: &TapConstants<'_>,
src: &SharedColors,
idx: usize,
kernel_w: f32,
) -> Option<(Vec3, f32)> {
let wf = facet_weight(centre.facet, g.facet_id[idx]);
if wf == 0.0 {
return None;
}
if let Some(sig) = g.path_sig
&& sig[idx] != centre.sig
{
return None;
}
let texel = src.load(idx);
if !texel.is_finite() {
return None;
}
let wn = normal_weight_unit(centre.normal, tap.normal_n[idx], tap.normal_power);
if wn == 0.0 {
return None;
}
let wd = depth_weight(centre.depth, g.depth[idx], tap.neg_inv_sigma_depth);
let wc = color_weight(centre.color, texel, tap.neg_inv_two_sigma_color_sq);
Some((texel, kernel_w * wf * wn * wd * wc))
}
#[inline]
fn atrous_pixel(
src: &SharedColors,
g: &GBuffers<'_>,
x: usize,
y: usize,
stride: i64,
tap: &TapConstants<'_>,
) -> Vec3 {
let center_idx = y * g.width + x;
let raw = src.load(center_idx);
let color = if raw.is_finite() { raw } else { Vec3::ZERO };
let facet = g.facet_id[center_idx];
if facet < 0 {
return color;
}
let centre = Centre {
facet,
sig: g.path_sig.map_or(0, |sig| sig[center_idx]),
depth: g.depth[center_idx],
normal: tap.normal_n[center_idx],
color,
};
let mut sum = Vec3::ZERO;
let mut weight_sum = 0.0f32;
for (ky, &hy) in B3_SPLINE.iter().enumerate() {
let row_tap = i64::try_from(ky).expect("a 5-tap index fits i64") - 2;
let Some(sy) = shifted(y, row_tap * stride, g.height) else {
continue;
};
for (kx, &hx) in B3_SPLINE.iter().enumerate() {
let col_tap = i64::try_from(kx).expect("a 5-tap index fits i64") - 2;
let Some(sx) = shifted(x, col_tap * stride, g.width) else {
continue;
};
let idx = sy * g.width + sx;
let Some((texel, w)) = tap_contribution(¢re, g, tap, src, idx, hy * hx) else {
continue;
};
sum += texel * w;
weight_sum += w;
}
}
if weight_sum > SIGMA_EPS {
sum / weight_sum
} else {
color
}
}
fn filter_rows(
src: &SharedColors,
dst: &SharedColors,
g: &GBuffers<'_>,
stride: i64,
tap: &TapConstants<'_>,
rows: Range<usize>,
) {
for y in rows {
for x in 0..g.width {
dst.store(y * g.width + x, atrous_pixel(src, g, x, y, stride, tap));
}
}
}
type PanicPayload = Box<dyn Any + Send>;
struct GateState {
phase: usize,
bands: usize,
claimed: usize,
finished: usize,
shutdown: bool,
failure: Option<PanicPayload>,
}
struct PhaseGate {
state: Mutex<GateState>,
changed: Condvar,
}
impl PhaseGate {
const fn new(bands: usize) -> Self {
Self {
state: Mutex::new(GateState {
phase: 0,
bands,
claimed: bands,
finished: bands,
shutdown: false,
failure: None,
}),
changed: Condvar::new(),
}
}
fn lock(&self) -> MutexGuard<'_, GateState> {
self.state.lock().unwrap_or_else(PoisonError::into_inner)
}
fn begin_phase(&self) {
{
let mut state = self.lock();
state.phase += 1;
state.claimed = 0;
state.finished = 0;
}
self.changed.notify_all();
}
fn claim(&self) -> Option<(usize, usize)> {
let mut state = self.lock();
if state.claimed >= state.bands {
return None;
}
let band = state.claimed;
state.claimed += 1;
Some((state.phase.saturating_sub(1), band))
}
fn finish(&self, failure: Option<PanicPayload>) {
let all_done = {
let mut state = self.lock();
state.finished += 1;
if state.failure.is_none() {
state.failure = failure;
}
state.finished == state.bands
};
if all_done {
self.changed.notify_all();
}
}
fn serve(&self, run_band: &(dyn Fn(usize, usize) + Sync)) {
while let Some((pass, band)) = self.claim() {
let outcome = catch_unwind(AssertUnwindSafe(|| run_band(pass, band)));
self.finish(outcome.err());
}
}
fn wait_done(&self) {
drop(
self.changed
.wait_while(self.lock(), |state| state.finished < state.bands)
.unwrap_or_else(PoisonError::into_inner),
);
}
fn work(&self, run_band: &(dyn Fn(usize, usize) + Sync)) {
let mut served = 0;
loop {
let (shutdown, phase) = {
let state = self
.changed
.wait_while(self.lock(), |state| {
!state.shutdown && state.phase == served
})
.unwrap_or_else(PoisonError::into_inner);
(state.shutdown, state.phase)
};
if shutdown {
return;
}
served = phase;
self.serve(run_band);
}
}
fn shutdown(&self) {
self.lock().shutdown = true;
self.changed.notify_all();
}
fn take_failure(&self) -> Option<PanicPayload> {
self.lock().failure.take()
}
}
struct ShutdownOnDrop<'a>(&'a PhaseGate);
impl Drop for ShutdownOnDrop<'_> {
fn drop(&mut self) {
self.0.shutdown();
}
}
fn run_scoped(
run_band: &(dyn Fn(usize, usize) + Sync),
bands: usize,
workers: usize,
passes: usize,
) {
let gate = PhaseGate::new(bands);
thread::scope(|scope| {
let _shutdown = ShutdownOnDrop(&gate);
for _ in 0..workers {
if thread::Builder::new()
.spawn_scoped(scope, || gate.work(run_band))
.is_err()
{
break;
}
}
for _ in 0..passes {
gate.begin_phase();
gate.serve(run_band);
gate.wait_done();
}
});
if let Some(payload) = gate.take_failure() {
resume_unwind(payload);
}
}
pub(super) fn run_passes(
buffers: &[SharedColors; 2],
g: &GBuffers<'_>,
tap: &TapConstants<'_>,
num_passes: u32,
num_threads: usize,
) -> usize {
let height = g.height;
if g.width == 0 || height == 0 {
return 0;
}
let band_target = if num_threads <= 1 {
1
} else {
num_threads.saturating_mul(BANDS_PER_THREAD).min(height)
};
let rows_per_band = height.div_ceil(band_target);
let bands = height.div_ceil(rows_per_band);
let passes = num_passes as usize;
let run_band = |pass: usize, band: usize| {
let first = band * rows_per_band;
filter_rows(
&buffers[pass & 1],
&buffers[(pass & 1) ^ 1],
g,
1_i64 << pass,
tap,
first..(first + rows_per_band).min(height),
);
};
if bands == 1 {
for pass in 0..passes {
run_band(pass, 0);
}
} else {
run_scoped(&run_band, bands, num_threads.min(bands) - 1, passes);
}
passes & 1
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::AtomicUsize;
#[test]
fn every_band_runs_once_per_pass_and_passes_do_not_overlap() {
const BANDS: usize = 13;
const PASSES: usize = 5;
let done: Vec<AtomicUsize> = (0..PASSES).map(|_| AtomicUsize::new(0)).collect();
let run = |pass: usize, _band: usize| {
if pass > 0 {
assert_eq!(
done[pass - 1].load(Ordering::SeqCst),
BANDS,
"pass {pass} started before the previous pass finished"
);
}
done[pass].fetch_add(1, Ordering::SeqCst);
};
run_scoped(&run, BANDS, 3, PASSES);
for (pass, count) in done.iter().enumerate() {
assert_eq!(count.load(Ordering::SeqCst), BANDS, "pass {pass}");
}
}
#[test]
fn a_panicking_band_unwinds_the_caller_instead_of_hanging() {
let run = |_pass: usize, band: usize| {
assert_ne!(band, 2, "deliberate test panic");
};
let outcome = catch_unwind(AssertUnwindSafe(|| run_scoped(&run, 6, 3, 2)));
assert!(outcome.is_err());
}
#[test]
fn the_caller_alone_drains_every_phase() {
let ran = AtomicUsize::new(0);
let run = |_pass: usize, _band: usize| {
ran.fetch_add(1, Ordering::SeqCst);
};
run_scoped(&run, 7, 0, 4);
assert_eq!(ran.load(Ordering::SeqCst), 7 * 4);
}
}