lapstack

GPU acceleration

The command-line tool has an optional CUDA path for the fusion and the aligner. It is a build feature, and it roughly halves to thirds the wall time of a run.

(The browser and desktop apps use WebGPU instead, on any GPU, and need none of this.)

Building

shell
cargo build --release --features gpu -p lapstack-cli

cudarc is built with dynamic loading, so CUDA is not needed at build time, and a binary built with the feature still runs on a machine without CUDA. Only --gpu and --gpu-align fail there, with a message; everything else works.

Running

shell
lapstack --gpu --gpu-align --align-coarsen 2 --save-depth -o stacked.tif frames/*.tif
OptionWhat moves to the GPU
--gpuThe fusion — the same kernels transcribed to CUDA. The accumulator pyramid, the best-energy planes and the winner map stay on the device; only the three RGB planes go up per frame and the tiny residual comes back. The depth pass runs there too
--gpu-alignThe aligner's cost search — and with it, the frames themselves

--gpu-align is the bigger win, and not only for the search. With it, a decoded frame is uploaded once and its luma and registration pyramid, the Nelder–Mead cost search, the warp, the brightness gains and the depth pass's focus slice are all computed on the device. The fuser folds the warped planes in place, and a frame comes back to the host only when something there asks for it — --save-aligned, or the weighted average.

What is left of a GPU frame is the decode and the upload, and the host holds no warped copies at all. That is where the peak memory goes.

Runtime requirements

PlatformWhat is needed
Linuxlibcuda from the driver and libnvrtc from the toolkit on the library path, and the nvidia_uvm module loaded
NixOSLD_LIBRARY_PATH=/run/opengl-driver/lib:<cudaPackages.cuda_nvrtc's lib output>/lib
Windowsnvcuda.dll ships with the display driver. Drop the two DLLs from NVIDIA's cuda_nvrtc redistributable zip — bin/nvrtc64_120_0.dll and nvrtc-builtins — next to lapstack.exe
Warning

On Windows, match the nvrtc major.minor to the driver's CUDA version (check nvidia-smi) or the PTX just-in-time compiler will reject the kernels.

What it buys

On 8280×5520 sixteen-bit frames, an RTX 3060 and a 128-thread host — the whole run, depth pass included:

RunWallFold (align + fuse + focus measure)DepthPeak RSS
25 frames, CPU26 s19 s (0.75 s/frame)6.0 s8.7 GB
25 frames, --gpu --gpu-align9.6 s5.1 s (0.20 s/frame)1.0 s6.2 GB
100 frames, CPU85 s74 s (0.74 s/frame)8.0 s12.0 GB
100 frames, --gpu --gpu-align26 s21 s (0.21 s/frame)1.9 s9.4 GB

The depth pass on the device runs the same stages as the browser's, multigrid included: slices are uploaded one at a time, only the two medians (the noise floor and the confidence scale) are taken on the host, and the maps come back.

How closely GPU and CPU agree

This matters if you care about reproducibility, so here it is precisely.

  • Fusion output is bit-exact with the CPU output. (One run in four differed in 637 of 45.7 million pixels, on energy ties, and could not be reproduced.)
  • With halo control, the weights are made, REDUCEd and folded on the device too, and the output differs from the CPU's by float rounding only.
  • CPU reruns are byte-identical to each other.
  • The depth maps are within 4 × 10⁻⁴ of full scale of the CPU's. A few pixels in a million of the confidence map differ, where a near-tie in the peak search falls the other way in float order.
  • GPU alignment evaluates the cost in FP32 and warps on the device (coordinates in double like the CPU warp, taps in FP32), so --gpu-align results differ from CPU-aligned ones in about 0.5 % of pixels. The transforms it finds are the same as the CPU's, to the last printed digit.

In short: --gpu alone is reproducible against the CPU path; --gpu-align changes the resampling arithmetic slightly, as any change of warp precision would.

When it does not help

The --no-align path on compressed input is decode-bound — about a second per frame for sixteen-bit PNG with four decoder threads — and the GPU cannot help with that. Uncompressed TIFF input decodes an order of magnitude faster.

Source: sites/lapstack/content/docs/cli/gpu.md