fix: progressive blur holds two levels at a time, not every level (#2092 review follow-up)

This commit is contained in:
Christopher Linnett
2026-10-29 19:22:28 +08:00
parent 280a400be4
commit b7242a8670
2 changed files with 21 additions and 11 deletions
+17 -9
View File
@@ -289,16 +289,24 @@ pub fn progressive_blur(img: &Image, iris: &Iris, radius: &[f32]) -> Image {
return bokeh_blur(img, iris, levels[0] as f64);
}
let (lo, hi, n) = (levels[0], levels[levels.len() - 1], levels.len());
let blurred: Vec<Image> = levels.par_iter().map(|&r| bokeh_blur(img, iris, r as f64)).collect();
// A pixel blends only the two levels around its radius, so the levels are made in order and
// only that pair is held: peak memory stays a few images whatever the level count, rather
// than one image per level. Each level's blur is parallel over its rows.
let mut out = Image::new(img.width, img.height);
out.data.par_iter_mut().enumerate().for_each(|(i, o)| {
let r = radius[i];
let f = ((r - lo) / (hi - lo) * (n - 1) as f32).clamp(0.0, (n - 1) as f32);
let k = (f.floor() as usize).min(n - 2);
let t = f - k as f32;
let (a, b) = (blurred[k].data[i], blurred[k + 1].data[i]);
*o = [0, 1, 2, 3].map(|c| a[c] + (b[c] - a[c]) * t);
});
let mut below = bokeh_blur(img, iris, lo as f64);
for (k, &r) in levels.iter().enumerate().skip(1) {
let above = bokeh_blur(img, iris, r as f64);
out.data.par_iter_mut().enumerate().for_each(|(i, o)| {
let f = ((radius[i] - lo) / (hi - lo) * (n - 1) as f32).clamp(0.0, (n - 1) as f32);
let kk = (f.floor() as usize).min(n - 2);
if kk + 1 == k {
let t = f - kk as f32;
let (a, b) = (below.data[i], above.data[i]);
*o = [0, 1, 2, 3].map(|c| a[c] + (b[c] - a[c]) * t);
}
});
below = above;
}
out
}
+4 -2
View File
@@ -294,8 +294,10 @@ fn dof_radii(cam: &CameraState, dof: &super::camera::Dof, world: Mat4, buf: &Buf
}
/// Pixels a padded blur buffer may have: the ~16 million layer buffers are held to
/// ([`crate::Renderer::raster_scale`]), so a blur never needs more memory than a large layer;
/// twice the buffer when that is larger, so a big buffer can still be blurred.
/// ([`crate::Renderer::raster_scale`]), or twice the buffer when that is larger, so a big buffer
/// can still be blurred. The blur holds a few images of this size at once whatever its level
/// count ([`super::bokeh::progressive_blur`]), so blurring a small plane costs no more memory than
/// blurring a large layer.
const DOF_PAD_BUDGET: f64 = 16.0e6;
/// Comp pixels per buffer pixel below which a plane isn't blurred. Such a plane covers almost no