Merge PR #1976: GUM-3201: Reduce guided-filter coefficient allocations

This commit is contained in:
francoisgn
2026-10-22 22:31:15 +03:00
7 changed files with 250 additions and 4 deletions
+4
View File
@@ -4,6 +4,10 @@ The CPU pipeline (`crates/pipeline`) is the reference ("oracle"). `lightcraft-gp
evaluates the same stages with wgpu compute shaders (WGSL) on Metal / Vulkan / DX12. Everything is
pure Rust (wgpu, naga); the drivers are the system's. No GL backend is compiled in.
CPU fast guided-filter allocation measurements and reproduction commands are documented in
[guided-filter-memory.md](guided-filter-memory.md). That optimization retains the full-size base
and does not change the GPU's coefficient buffers.
Warped geometry uses a CPU-computed coverage bit mask for the source boundary.
The CPU reference evaluates that boundary in double precision; GPU float
rounding otherwise can turn a blank edge pixel into a photo pixel. The mask
+53
View File
@@ -0,0 +1,53 @@
# CPU fast guided-filter memory
`local::guided_fast` computes blurred coefficients on the same reduced grid as before, then
samples them while applying `a * p + b`. It keeps the raster resizer's weights, boundary
normalization and horizontal-then-vertical accumulation order. Odd dimensions therefore use
their actual reduced/full dimension ratios. Four coefficient row pairs and one bias row are cached
per active 32-row band; adjacent output rows reuse their horizontal samples.
The two full-resolution coefficient planes and their resize intermediates are gone. The returned
full-resolution base remains: downstream CPU tone mapping and the spatial-plane cache need it.
The step-1 filter, Box reduction, Gaussian coefficients, V2's median input, process selection and
Draft sigma cap are unchanged. The GPU implementation is unchanged; this reduces CPU memory only.
## Reproduce
The dev-only example includes the previous materialized algorithm and uses the workspace's
existing `dhat` allocator. No allocator or profiling dependency is added to product builds.
```sh
cargo build --release -p lightcraft-pipeline --example guided_memory
RAYON_NUM_THREADS=1 target/release/examples/guided_memory old 6000 4000 120 15
RAYON_NUM_THREADS=1 target/release/examples/guided_memory new 6000 4000 120 15
RAYON_NUM_THREADS=1 target/release/examples/guided_memory old 6000 4000 120 1 --heap
RAYON_NUM_THREADS=1 target/release/examples/guided_memory new 6000 4000 120 1 --heap
```
If `CARGO_TARGET_DIR` is set, use that directory instead of `target` for the executable.
Arguments are mode, width, height, integer sigma and timing iterations. The example warms up
before measurement; `--heap` counts one filter call with the source allocated beforehand.
Time the runs without `--heap`: allocation profiling significantly changes timings. It reports
the minimum wall time; on a shared machine repeat when other builds/renders have stopped.
Use `LIGHTCRAFT_PROFILE=1` and `cargo xtask bench` for broader pipeline measurements.
## Observed allocation and time
Measured 2026-10-16 UTC, macOS aarch64, Rust 1.96.0, release build, one Rayon thread. Bytes are
requested heap bytes counted by dhat, not process RSS. Timings are minimums of 15 unprofiled
calls on a shared machine with concurrent builds; they are indicative, not a speed guarantee.
| Dimensions / sigma / step | Old peak bytes | New peak bytes | Old total allocated bytes | New total allocated bytes | Old / new wall ms |
|---|---:|---:|---:|---:|---:|
| 6000 × 4000 / 120 / 16 | 289,125,000 | 97,780,856 | 313,083,488 | 135,643,856 | 42.135 / 45.131 |
| 1601 × 1067 / 24 / 8 | 20,822,412 | 7,331,172 | 25,102,604 | 11,562,560 | 3.359 / 3.121 |
The 24 MP result saves about 191 MB of peak allocation (66%). Its **96,000,000-byte output is
included**; its **96,000,000-byte input is excluded**. Application RGB images, log luminance,
V2 median input and its construction temporaries, other spatial planes and caches also remain
outside this isolated measurement. More Rayon threads can hold more band scratch concurrently.
This is not a bound on total pipeline memory.
Regression tests compare the sampled result exactly against materialized bilinear resizes for
empty/singleton/one-dimensional, odd/even and multiple-band images; flat fields, signed texture,
edges and impulses; small/full and reduced filters; and median tone bases.