Denoise a whole frame in one call where the GPU takes any size

A fixed 1408 tile is exact only in its centre, and Best keeps 896 of
every 1408 it computes: 2.47 photosites of work for each one kept. The
tiler now takes a network of any size as well as a square one, and
plans the frame as the fewest equal tiles under the rung's limit --
one tile, the whole frame and its reflected border, whenever it fits.
If the first call of a plan fails, as a GPU out of memory does, the
kept centre is halved and the frame planned again.

Each shipped network names its any-size sibling (mosaic-best.onnx
beside mosaic-best-1408.onnx). OnnxNet::open takes it where the engine
runs whole frames and the file is installed, and the 1408 tiles
otherwise; open_tiled forces the tiles, and denoise_raw's DR_PLAN=tiles
uses it to compare. The cache key stays on the fixed model: the output
is the same network's. Tests hold any-size tiles, a grid of them and a
plan rebuilt after a failure to the square tiles' answer in every Bayer
phase.
This commit is contained in:
2026-10-06 21:47:19 -04:00
parent 56f4180347
commit 9cba420fd5
6 changed files with 461 additions and 108 deletions
+23 -5
View File
@@ -11,7 +11,9 @@
//! camera RGB — for comparison with the training repo's own path
//! (`tools/compare_rust.py` in darkroom-denoise). `DARKROOM_ORT_DIR` points
//! at an ONNX Runtime build; the engine's cache goes to `DR_ENGINE_CACHE` or
//! a temporary directory.
//! a temporary directory. The whole-frame network (`mosaic-best.onnx` beside
//! the fixed file) runs where the rung takes any size; `DR_PLAN=tiles` keeps
//! the 1408² tiles anyway, to compare the two.
use std::path::PathBuf;
use std::time::{Duration, Instant};
@@ -38,6 +40,12 @@ fn main() {
let model = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../models/denoise")
.join(shipped.file);
let whole = model.with_file_name(shipped.whole);
let tiles_only = std::env::var("DR_PLAN").is_ok_and(|p| p == "tiles");
let mut models = vec![(Role::Denoiser, model.clone())];
if whole.is_file() && !tiles_only {
models.push((Role::WholeDenoiser, whole));
}
let cache = std::env::var_os("DR_ENGINE_CACHE")
.map(PathBuf::from)
.unwrap_or_else(|| std::env::temp_dir().join("dr-denoise-engines"));
@@ -48,7 +56,7 @@ fn main() {
.into_iter()
.collect(),
cache_dir: cache,
models: vec![(Role::Denoiser, model.clone())],
models,
embedded: Vec::new(),
ceiling: None,
threads: 0,
@@ -101,10 +109,20 @@ fn main() {
noise.col
);
let mut net = OnnxNet::from_path(&model, shipped.halo).expect("model");
let mut net = if tiles_only {
OnnxNet::open_tiled(&model, shipped)
} else {
OnnxNet::open(&model, shipped)
}
.expect("model");
println!(
"rung {}",
net.rung().map(|r| r.label()).unwrap_or("?")
"rung {} · {}",
net.rung().map(|r| r.label()).unwrap_or("?"),
if net.whole_frame() {
"whole frame"
} else {
"1408² tiles"
}
);
let t = Instant::now();
let rgb = dr_denoise::denoise(&raw, &noise, &mut net, &mut |done, total| {