Meshroom / AliceVision photogrammetry on AMD Radeon GPUs, via HIP.
AliceVision's dense reconstruction (DepthMap, the stage Meshroom needs a GPU for) is
written in CUDA. An official SYCL backend was merged upstream in May 2026
(AliceVision#2077, closing the
eight-year #439) but has not appeared
in any release, resolves to off when AdaptiveCpp is absent, and has no published results on
AMD hardware. Cheshire is a HIP port you can download and run today, on Windows and Linux:
the same CUDA kernels compiled through a small compatibility layer, plus a memory bridge
that lets the stage spill from VRAM into system RAM instead of failing, validated
per architecture against a CUDA node's output on RDNA1, RDNA2 and RDNA4 cards.
The cat that grins on any hardware.
Two things here are not off-the-shelf. The port itself is close to mechanical (a compat
header does what hipify would), but it is validated: every architecture is compared
against a CUDA reference with a stated metric, and the porting bugs found on the way are the
kind that produce wrong output rather than errors (HIP dropping surf2Dwrite into 16-bit
float arrays; GPU atomics into mapped host memory silently wrong on Linux unless the memory
is non-coherent). The memory bridge is the novel part: it decides what spills to system RAM
by buffer class, and the policy is set by measurement, not by intuition. With the default
fine-grained host mapping, 186 MB of texture-sampled camera images behind PCIe cost 22x while
6 GB of streamed volumes cost 4.7x; coarse-grained mapping turns the images to 1.0x. That
number is why the design is what it is.
| Meshroom node | upstream | Cheshire | status |
|---|---|---|---|
| DepthMap | CUDA only | HIP port + VRAM-to-RAM memory bridge; the host's work kept out of the device's way | validated RDNA1/2/4, Windows + Linux; bit-identical to native across caps. v0.4.1: the T cameras and the tiles' depth lists from each camera's own landmarks, the tiles and the batches overlapping the device's work, the headers on every core: the 884-photo False Door's DepthMap 5,587 s -> 1,733 s on the RX 9070, the same maps (notes). v0.4.2: the GPU stages without double precision, exactly: the False Door's DepthMap chunks 1,878 s -> 1,297 s (notes). v0.4.3: the image uploads without device-wide waits, under the tiles and the decodes: 1,263 s -> 1,142 s, the same maps (notes) |
| FeatureMatching | CPU (kd-tree) on every vendor | exact GPU brute-force 2-NN (HIP; the source also builds as CUDA), plus exact CPU work in AC-RANSAC (docs/15) | validated end to end (v0.2.5): 592 s -> 75 s on 107 photos, same reconstruction. Geometric verification followed in v0.2.15: 566 s -> 351 s, byte-identical match file, and the profile is why it stayed on the CPU. v0.3.8: AC-RANSAC skips the models that cannot win and computes the epipolar residuals in one vectorised loop, both exact: geometric filtering 36.8 s -> 16.4 s on 41 views at Meshroom 2025.1's 50,000 iterations (notes). v0.4.1: the search on the cards' integer dot-product units, knn2_wmma on RDNA4 and knn2_dot4q on RDNA2 and NVIDIA, exact by construction (41 views 9.9 s -> 4.0 s on the RX 9070, docs/07), and the search beside the geometric filter. v0.4.4: the 7-point fits four at a time in AVX2 lanes, the descriptors kept on the GPU, the next pair's search queued during the filter: the 884-photo False Door's FeatureMatching 77-85 s -> 43 s, the same matches (notes) |
| FeatureExtraction | CUDA (PopSift) or CPU | HIP PopSift port (docs/14) | done (v0.2.13): 2021 s -> 26 s on 41 views (RX 9070), and better than the CPU path rather than merely faster — 88,463 landmarks against 78,372 and RMSE 1.0377 against 1.03997 px. Validated on RDNA4, RDNA1 and RDNA2 across two runtimes and both systems, landmarks within 0.11 %; found and reported an upstream PopSift bug (popsift#193) |
| DepthMapFilter | CPU | GPU vote pass (HIP / CUDA source) + a shared decoded-map cache | validated (v0.2.6): 123.5 s -> 26.5 s on 107 photos (RX 9070), 317 s -> 26.9 s on 41 views on an i3 + RX 5500 XT, bit-identical; found and replicated an upstream vote-buffer quirk; v0.2.9 cache: 17.8 s -> 12.7 s, byte-identical |
| Meshing | CPU | GPU graph-weight votes + weakly-supported-surfaces pass, GPU min-cut (push-relabel, docs/12), GPU nearest-neighbour search and votes for the visibility passes (docs/13), exact CPU fixes around them (docs/11) | done (v0.2.7 through v0.2.12, v0.2.16, v0.3.5): 510 s -> 101 s on 107 photos (RX 9070), 491 s -> 111 s on 41 views on an i3 + RX 5500 XT; the cut labelling identical to Boykov-Kolmogorov's and the nearest neighbours identical to nanoflann's on every query. Every CPU change is verified identical in-process; the one that was not, upstream running one inversion round whatever it was asked for, was taken upstream (alicevision/AliceVision#2179) and is upstream's own code from v0.4.1 (docs/11). v0.3.5 put the visibility votes on the device (the 884-view Meshing on an i3 + RX 6750 XT: 490 s -> 451 s); the tetrahedralisation stays on the CPU |
| Texturing | CPU | GPU Laplacian pyramid + rasterisation, parallel camera selection (HIP / CUDA source), exact CPU fixes in the UV unwrap (docs/10), edge padding and the atlas downscale on the GPU, a direct textured-OBJ writer | done (v0.2.8, v0.2.16): 165.8 s -> 79.3 s on 107 photos (RX 9070), 271.5 s -> 102.5 s on 41 views on an i3 + RX 5500 XT, textures inside the CPU's own run-to-run band; v0.2.16 took the UV unwrap 14.4 s -> 8.6 s with a byte-identical texturedMesh.obj, and gains most on the slowest hardware (51.9 s -> 16.8 s on a 2011 Bulldozer). v0.3.2 moved the edge padding to the GPU (0 of 67,108,864 texels differ) and writes the textured OBJ directly (0 faces differ); v0.3.3 moved OpenImageIO's lanczos3 downscale there too (0 of 50,331,648 channels differ; Texturing on the engine bay 176 s -> 124 s) (docs/04). v0.4.1: the image cache evicts by load order, which ended most images being read twice on large sets (the False Door's Texturing 2,480 s -> 1,245 s), and the UV layout follows upstream's fix of a camera-ranking bug this project reported (alicevision/AliceVision#2181) |
| PrepareDenseScene | CPU | every core instead of three threads, the undistortion map once per intrinsic, a direct 8-bit JPEG read, cheaper EXR compression; on four-thread hosts the undistortion on the GPU | done (v0.2.9, v0.3.3, v0.3.4, v0.3.8): 36 s -> 30 s on 107 photos at v0.2.9; the undistortion map and the direct read are exact, and the EXRs are ZIP at level 1 instead of ZIPS at 4 (the same pixels). On a twelve-thread desktop the node is codec and disk work and the gains are small. On a four-thread i3 it was all CPU, and v0.3.8 took 40 photos of a 524-photo job from 71.2 s to 43.8 s, with libdeflate for the EXRs (Linux) and the undistortion on the GPU, both exact. CheshireJPG's GPU decode is there opt-in (v0.3.5, CHESHIRE_GPU_JPEG=1) and no faster |
| StructureFromMotion | CPU (Ceres) | Grin, Cheshire's own bundle-adjustment solver: Ceres' algorithm step for step, the large solves on the GPU (docs/notes/ba-own-solver.md); exact rewrites of the host code around it; the fix for Meshroom #2344 (a resection pass that ends without its bundle adjustment gets one, and the local-BA graph cannot throw) | v0.3.8: the features' and colours' reads, exact: 307.8 s -> 240.9 s on the False Door. v0.3.7 (notes): 1140 s -> 284 s on the 884-photo False Door (RX 9070 box), bundle adjustment 675 s -> 47 s. On every build and card tested the GPU's solves give the CPU's bytes, and SfM repeats itself byte for byte. v0.3.3: the invalid map<K, T> key crash of Meshroom #2344, reproduced three times on an 884-photo set, found and fixed (docs/04); the eighth paired node |
| ImageMatching | CPU (vocabulary tree above 200 photos) | opt-in pairing by GPS radius (CHESHIRE_GPS_PAIRING_RADIUS=<metres>), for surveys the vocabulary tree pairs badly; GPS read from cameras that omit the altitude reference |
v0.3.5, the ninth paired node; v0.3.6 the altitude fix. On a 524-photo drone survey the vocabulary tree placed 90 views; a 200 m radius placed 521, as exhaustive matching does, from 11 % of its pairs in a tenth of the matching time (docs/04) |
| TracksBuilding, RelativePoseEstimating, SfMBootStrapping, SfMExpanding, SfMTransform, SfMColorizing, IntrinsicsTransforming, ExportImages: upstream's new SfM pipeline (Meshroom 2025.1's Photogrammetry Experimental) | CPU (Ceres) | the SfM work ported to the new nodes: AC-RANSAC's bound and its iterations in batches on every core, a random generator per track, the tracks file parsed straight into structs, ExportImages one image per thread with each camera's warp map built once (on four-thread hosts on the GPU); Grin and the colours' 8-bit read carried over by themselves | v0.4.0, eight more paired nodes on Meshroom 2025.1: on 41 photos SfMExpanding 334 s -> 29 s and the Experimental graph's nodes 743 s -> 357 s (RX 9070 box; the GPU nodes are Cheshire's in both). Exact but for the triangulation's draws, which now repeat run to run where upstream's do not (notes). v0.4.1: SfMExpanding's next views in a total order, so an 884-photo job repeats itself too, and the host passes on every core: the new chain on the False Door 1,168 s -> 699 s (notes) |
| MeshFiltering | CPU | stays on the CPU (small) |
Everything installs by pairing: one script swaps the node binaries (DepthMap, FeatureExtraction, FeatureMatching, DepthMapFilter, Meshing, Texturing, PrepareDenseScene, StructureFromMotion and ImageMatching, and on Meshroom 2025.1 the eight of upstream's new SfM pipeline) in an existing Meshroom 2023.3 or 2025.1 install and keeps Meshroom's own beside them, choosing per run by the card present. On a 12-thread desktop the 107-photo engine bay job went from 39 minutes with the CUDA-era layout to 30 at v0.2.5, when the GPU matcher joined DepthMap (docs/07); every other node above has joined or got faster since. The 884-photo False Door, through Photogrammetry Experimental Fast Ransac on the same box (an RX 9070), took 10,930 s with v0.4.0 (already given v0.4.1's matcher kernel) and takes 5,269 s with v0.4.1 (docs/04).
Read the upstream column again: DepthMap is the only stage Meshroom puts on a CUDA GPU. Feature
matching, depth map filtering, meshing and texturing are on the CPU for everyone, NVIDIA included.
Every one of the ports above was written as CUDA source and compiled through a compat header for
HIP, so building them as CUDA costs nothing but a configure - and an NVIDIA user gets the five
stages plus GPU SIFT and the memory bridge, none of which are upstream.
DepthMap is the exception and deliberately so: on CUDA it is upstream's own kernels, and a packaged run is byte-identical to a Meshroom CUDA 11.3 reference, checked from a clean extraction of the release tarball rather than from a build tree. Nobody should switch DepthMap backends for its own sake; the reason to take the CUDA package is everything around it.
Same photos, same SfM, same DepthMap parameters as the CUDA reference (Meshroom 2023.3 on a GTX 1080 Ti); only the GPU stage differs. Metrics are per view over pixels valid in both maps. Times are the DepthMap stage only. The CUDA reference ran as Meshroom runs it, in chunks of 12 views (four chunks for 41 views: 105.4 + 111.1 + 106.3 + 56.2 s); the HIP times are one invocation over all views. The apples-to-apples numbers are the two cards run inside real Meshroom jobs on the same node, also four chunks: RX 6750 XT 352 s, RX 5500 XT 594 s (both jobs reconstructed the full 41-photo mesh, within 2 % of the CUDA job's vertex count).
| GPU | OS | 6 views | 41 views | per view (41) | valid masks | median rel. depth error | within 1 % (median view, 6 / 41) |
|---|---|---|---|---|---|---|---|
| GTX 1080 Ti (CUDA reference, 4 Meshroom chunks) | Linux | 31.8 s | 379.0 s | 9.2 s | |||
| GTX 1080 Ti, CUDA 11.6 (Meshroom 2023.3 Windows build), same host as the RX 6750 XT Windows rows | Windows | 40.0 s | 287.1 s | 7.0 s | 37 / 41 identical to the reference | 0.0000 | 100 % / 100 % (worst view 92.9 %) |
| Radeon RX 9070, RDNA4 | Windows | 17.4 s | 124.4 s | 3.0 s | identical | 0.0000 | 98.9 % / 98.7 % |
| Radeon RX 6750 XT, RDNA2 | Linux | 31.0 s | 226.1 s (352 s in 4 Meshroom chunks) | 5.5 s | identical | 0.0000 | 97.5 % / 98.1 % |
| Radeon RX 6750 XT, RDNA2, HIP SDK 6.2 build | Windows | 28.1 s | 190.3 s | 4.6 s | identical | 0.0000 | 98.7 % / 98.7 % |
| Radeon RX 6750 XT, RDNA2, v0.2.3 bundle | Linux | 28.0 s | 205.7 s | 5.0 s | identical | 0.0000 | 97.5 % / 98.1 % |
| Radeon RX 5500 XT, RDNA1 | Linux | 60.7 s | 447.7 s (594 s in 4 Meshroom chunks) | 10.9 s | identical | 0.0000 | 97.5 % / 98.1 % |
| Radeon RX 5500 XT, RDNA1, v0.2.3 bundle | Linux | 52.4 s | 396.9 s | 9.7 s | identical | 0.0000 | 97.5 % / 98.1 % |
| Radeon RX 5500 XT, RDNA1, v0.2.5 bundle | Linux | 396.4 s | 9.7 s | identical | 0.0000 | 97.5 % / 98.1 % |
Per-view cost on every HIP card is flat between 6 and 41 views (the port scales linearly);
the CUDA reference's per-view cost rises from 5.3 s to 9.2 s across the chunked run. Until
2026-09-15 this table listed the CUDA 41-view time as 105.5 s, which was the first chunk
alone; the corrected figure is the sum of all four (data/ref/monstree-full/DepthMap/*/[0-3].log).
Three different comparisons appear in this repo, and they have three different answers.
All metrics are per view over pixels valid in both maps (scripts/compare_depthmaps.py;
tables in docs/validation).
| comparison | validity masks | median rel. depth error | pixels within 1 % | verdict |
|---|---|---|---|---|
| same card, any bridge configuration vs the uncapped run | identical | 0 | 100 % (every pixel equal) | bit-identical |
| RX 5500 XT vs RX 6750 XT (RDNA1 vs RDNA2), same HIP build | identical | 0 | 100 % (every pixel equal) | bit-identical |
| RX 9070 vs RX 6750 XT (RDNA4 vs RDNA2), same HIP build | identical | 0 | 97.0-98.5 % | not bit-identical: p95 error 0.07-0.24 % |
| RX 6750 XT under Windows / HIP 6.2 vs the same card under Linux / HIP 7.2 | identical | 0 | 97.1-98.7 % | not bit-identical: same silicon, different compiler and runtime |
| GTX 1080 Ti, CUDA 11.6 on Windows vs GTX 1080 Ti, CUDA 11.3 on Linux (the reference itself) | 41 / 41 | 0 | 100 % median view, 92.9 % worst | 37 / 41 depth maps bit-identical; the other four differ by up to 7.2 % of pixels. CUDA is not bit-identical to CUDA across builds either |
| this tree built as CUDA 12.9 vs the CUDA 11.3 reference, same GTX 1080 Ti | 41 / 41 | 0 | 100 % (every pixel equal) | byte-identical, 41 / 41 depth maps and 41 / 41 sim maps - and 1.80x faster (211 s vs 379 s). AliceVision 3.1 vs 3.4-dev and CUDA 11.3 vs 12.9 both contribute exactly nothing |
| any HIP card vs the CUDA GTX 1080 Ti | identical | 0 | 97.5-98.9 % | same noise floor as RDNA4 vs RDNA2 |
So the port is deterministic (same inputs, same build, same architecture family, same bits), and the 1-3 % of pixels that differ by more than 1 % between RDNA4 and RDNA2, between two toolchains on the same card, or between any AMD card and CUDA, is the algorithm's noise floor: texture-filter and FMA rounding propagating through SGM's argmin, not a port defect. The same 1-3 % appears between two AMD generations running identical code, between two compilers on identical silicon, and between two CUDA builds on the same NVIDIA card (the reference disagrees with a Windows CUDA 11.6 run of itself on 4 of 41 views, one of them by 7.2 % of pixels), which is what rules out the port as the cause.
Since 2026-09-20 that argument no longer rests on circumstantial evidence. This same tree, same patches, built as CUDA instead of HIP, is byte-identical to the CUDA 11.3 reference on all 41 views. Every patch this project carries is therefore provably neutral, and the 1-3 % is AMD hardware and compiler float behaviour with nothing else mixed in (docs/18).
Measured on the RX 9070 (hip/tests/membridge_probe.hip), the tiers the bridge chooses between:
| memory | kernel streaming read |
|---|---|
VRAM (hipMalloc) |
585-619 GB/s |
mapped system RAM (hipHostMalloc, PCIe 4.0 x16) |
24.6-26.6 GB/s |
hipMallocManaged |
26.6 GB/s (no page migration on Windows) |
| pinned host copies | 28 GB/s each way |
On Windows the driver already lets hipMalloc run past VRAM into system RAM; on Linux it fails
hard. (Mapped host memory is real system memory on both: hip/tests/host_backing.hip reads it at
28 GB/s against 615 GB/s for VRAM and it leaves free VRAM untouched; Task Manager's "dedicated GPU
memory" for such a process is a commitment figure, not residency.) The bridge (hip/compat/include/cheshire/bridge.h) makes both behave the same, and v2
decides what spills by buffer class instead of by arrival order. Measured, one class at a
time behind PCIe, every run bit-identical:
| spilled to system RAM (6 views) | fine-grained host memory | coarse-grained (shipped) |
|---|---|---|
| nothing | 20.6 s | 20.2 s |
| depth/sim maps (879 MB) | 35.9 s (1.7x) | 25.5 s (1.3x) |
| similarity volumes (6.0 GB) | 96.4 s (4.7x) | 76.6 s (3.8x) |
| camera images (186 MB) | 460 s (22x) | 20.4 s (1.0x) |
The host tier is coarse-grained (hipHostMallocNonCoherent): the GPU caches it, atomics work,
and the texture-sampled camera images stop costing anything. Images stay resident regardless
(the planner reserves VRAM for them), volumes and maps spill, and the DepthMap planner sizes
its tile parallelism from the bridge's budget instead of hipMemGetInfo:
| VRAM available | v1 (arrival order, planner unaware) | v2 |
|---|---|---|
| 1.5 GB | 47.7 s, 188 spills | 20.0 s, 0 spills |
| 1 GB | 20.3 s, 0 spills | |
| 500 MB (below one tile) | fails upstream | 47.2 s, runs |
Tile parallelism costs nothing to give up on this GPU, so a card with 1 GB to spare runs the stage at full speed. Design, knobs and every table: docs/02-memory-bridge.md.
FeatureMatching is the second GPU-shaped stage, and upstream has no GPU path for it on any vendor.
hip/port/gpu_matcher/ is an exact brute-force 2-NN on the GPU behind AliceVision's
RegionsMatcher (taken for ANN_L2 / BRUTE_FORCE_L2 whenever a device is present; the same
source builds as HIP or CUDA), byte-identical to the CPU brute force. Engine bay set, 107 phone
photos, RX 9070: the FeatureMatching node from 592 s to 75 s, the matching stage from 543 s to
40.7 s, and the reconstruction unchanged (107 / 107 cameras, residual RMSE 1.694 px vs 1.712,
mesh within 0.3 %). The pairing scripts swap this binary in next to DepthMap. Details and the
Meshroom 2023.3 chunking compatibility in docs/07-gpu-matcher.md.
| card | uncapped | 2 GB cap | 1 GB cap |
|---|---|---|---|
| RX 9070, Windows | 499.6 s (30 tiles) | 558.7 s (1 tile, no spills) | 2871.6 s (volumes behind PCIe) |
| RX 6750 XT, Linux | 744.1 s (20 tiles) | 749.9 s (1 tile, no spills, after two bridge fixes) | 4035 s |
Capped runs are bit-identical to uncapped on Windows (41 / 41, twice); on Linux 40 / 41, the odd
view differing by 110 pixels at 1e-6. The series produced two bridge fixes (a 4 MB floor under which
nothing spills, and an image reserve net of the images already resident: the Linux 2 GB cap went
from 863 s with 6047 spills to 749.9 s with none) and a hard floor: at 1 GB the SGM volumes
themselves live behind the link and the job runs 4-5x slower, which is the price of running where
upstream refuses. Details in docs/02-memory-bridge.md.
- HIP drops
surf2Dwritestores into 16-bit float arrays, on Windows and Linux alike; reads are fine. AliceVision's mip chain is built through a buffer copy instead. - Linux ROCm 7.2 has no
hipMallocMipmappedArrayon RDNA1 or RDNA2, the two architectures run on Linux here (and WSL2 has no textures at all). Mipmaps are emulated in the compat layer as one texture per level, in array or pitched linear memory: bit-identical to native mipmaps on the RX 9070 and on the RX 6750 XT (41 / 41 views), so the Windows build keeps native and the Linux bundle emulates on every architecture. Emulation used to cost 21 % (RX 9070, 6 views: 19.9 s vs 16.5 s) and 22 % (RX 6750 XT, 41 views: 232.3 s vs 190.3 s), which was the whole Linux-vs-Windows gap on that card. The disassembly showed why: the per-level texture handles lived in a device-side table, and the compiler could not prove the table index wave-uniform, so every sample fetched its descriptor with vector loads and tenv_readfirstlanes. The level descriptors are now packed into fixed-stride constant-memory slots addressed by arithmetic, with a run-time uniformity check that takes one scalar descriptor load on the common path (the per-pixel levels ofuseConsistentScalefall back to an out-of-line waterfall). Emulation now costs 4 % on the RX 9070 (17.2 s) and 9 % on the RX 6750 XT (208.1 s), still bit-identical; the v0.2.3 Linux bundle takes the RX 5500 XT from 447.7 s to 396.9 s and the RX 6750 XT from 226.1 s to 205.7 s on the 41-view set, byte-identical output. The bit-identity is expected rather than remarkable: AliceVision samples its mip chain only at integer levels (level = log2(scale / minDownscale)), where trilinear filtering reduces to bilinear on one level. Linear levels are what lets the bridge account for camera images. - GPU atomics into mapped host memory are silently wrong on Linux unless the memory is
allocated non-coherent: on an RX 6750 XT,
atomicMininto default (fine-grained) host memory fails on every element whileatomicAddworks, and both are right onhipHostMallocNonCoherentmemory (hip/tests/host_atomics.hip; Windows passes all cases). Anything that spills a buffer kernels do atomics on, LLM runtimes included, needs to know: standalone write-up in docs/notes/gpu-host-memory-on-rocm.md. - Fine-grained host memory is the wrong tier for texture-sampled data: with the default mapping, 186 MB of camera images behind PCIe cost 22x while 6 GB of streamed volumes cost 4.7x; allocated coarse-grained, the device caches them and the images cost nothing.
- ROCm for Windows installs as pip wheels, no admin installer. CMake refuses to mix
cl.exewith clang for HIP: useclang-clfor both.-fgpu-rdcis broken on Windows, so the device code is compiled as one unity translation unit. - A relocatable bundle needs things the dependency walkers never see: HIP loads the
code-object manager (
libamd_comgr/amd_comgr0702.dll) at runtime on both OSes, and without it the GPU simply "does not exist". On Linux a WSL build box also ships the/dev/dxgflavour oflibhsa-runtime64, which must be swapped for the KFD one. With those in place RDNA1 works natively on ROCm 7.2.
If you just want to use it, USING.md is the guide - install, check it is really on the GPU, what the error codes mean, and the dozen settings worth knowing. The rest of this file is what was built and why.
Binaries are on the v0.4.5 release; the data sets and references are on v0.1.0 and unchanged, the depth maps being bit-identical between the two:
| asset | size | contents |
|---|---|---|
cheshire-alicevision-windows-x64.zip (v0.4.5) |
194 MB | one Windows package for every AMD card. Eleven GPU payloads across both HIP runtimes - gfx1010/1012 (RX 5500-5700), gfx1030/1031/1032/1034 (RX 6000), gfx1033/1035/1036 (RDNA2 APUs), and gfx11-generic + gfx12-generic for RDNA3/RDNA4 and future chips in those families (GPU SIFT included: from v0.4.4 PopSIFT runs from the generic code objects too, docs/16). cheshire-detect.exe asks the card which it needs, so there is nothing to choose; cheshire-run.cmd runs a node straight from it, meshroom-pair.cmd + launcher pair it into Meshroom |
cheshire-alicevision-cuda-windows-x64-cuda12.9.zip (v0.4.5) |
109 MB | the same stages for NVIDIA, Windows. GPU SIFT, matcher, depth map filter, meshing votes and texturing, plus the memory bridge; cudart is bundled, so no CUDA toolkit is needed - only the driver. Paired, it runs on the NVIDIA card by itself (from v0.3.8; with v0.3.0 to v0.3.7 set CHESHIRE_BACKEND=cheshire) |
cheshire-alicevision-hip-linux-x64-rocm7.2.tar.gz (v0.4.5) |
120 MB | relocatable Linux bundle with the GPU matcher, depth map filter, meshing votes, texturing and the packed-slot mipmap sampler, code objects for RDNA1 by name (gfx1010/1011/1012), one generic code object each for RDNA2, RDNA3 and RDNA4 (gfx10-3-generic, gfx11-generic, gfx12-generic: the APUs and chips not out yet included) and Vega (gfx900/906, untested); GPU SIFT for the same RDNA targets (and gfx1013), not Vega, which takes CPU SIFT (v0.4.4 checks the loaded PopSIFT for the card's code first); needs only amdgpu + /dev/kfd and glibc 2.35 or newer (Ubuntu 22.04, Debian 12, Mint 21 and later, from v0.4.5; earlier releases needed 24.04); validated on the RX 6750 XT (and the RX 5500 XT in earlier releases) |
cheshire-alicevision-cuda-linux-x64-cuda12.9.tar.gz (v0.4.5) |
48 MB | the same stages for NVIDIA, Linux. libcudart bundled and no libcuda (the driver's, not ours); glibc 2.35 or newer, as the AMD bundle; the 41-view depth and similarity maps from a clean extraction of the tarball (82 files) were byte-identical to the Meshroom CUDA 11.3 reference in v0.3.3 (GTX 1080 Ti) and v0.3.4 (GTX 1050 Ti) |
monstree-mini6-meshroom-cache.tar.gz (v0.1.0) |
383 MB | 6-view Meshroom 2023.3 cache: CameraInit, SfM, PrepareDenseScene and the CUDA DepthMap reference |
monstree-full-cuda-reference.tar.gz (v0.1.0) |
680 MB | 41-view SfM + CUDA DepthMap reference (GTX 1080 Ti) |
cheshire-hip-depthmap-outputs.tar.gz (v0.1.0) |
966 MB | the HIP depth maps behind the table above (RX 9070 6 + 41 views, RX 5500 XT, RX 6750 XT) |
Three of the four packages in v0.4.5 passed on their own hardware, each as the file you download (docs/04):
- the Windows AMD zip on the RX 9070: the full gate through Meshroom 2025.1 (the 19-configuration mini6 matrix and the 41-view set) and a mini6 check through Meshroom 2023.3, every depth map v0.4.4's;
- the Linux AMD package on the RX 6750 XT and (a build of the same code, see the notes) the Linux NVIDIA package on a GTX 1080 Ti, through mini6 and 41 views, every depth map the previous gate's on that card; both Linux packages load on a bare Ubuntu 22.04.
The Windows NVIDIA zip ships on its build checks and a CPU-only run of its new-pipeline programs, as in v0.4.0 to v0.4.4: its test box is still down, as is the Windows run of the hip6.2 payloads (RDNA1 and RDNA2 under Windows) (notes).
v0.4.5 builds the Linux packages on Ubuntu 22.04 (glibc 2.35, GCC 12), so they run on Ubuntu 22.04, Debian 12, Mint 21 and newer instead of only 24.04-class systems, with the same depth maps as v0.4.4. The Windows AMD package checks the CPU before choosing a payload: on one older than the payload needs it names the missing feature and, paired into Meshroom, runs Meshroom's own binary instead of crashing. CPU-specific (AVX2) builds were measured and dropped: the exact one was no faster. In full: docs/releases/0.4.5.md.
v0.4.4 halves FeatureMatching on large sets, exactly: the geometric filter's 7-point fits run four at a time in AVX2 lanes with Eigen's arithmetic, each view's descriptors stay on the GPU for all its searches, and the GPU searches the next pair while the CPU filters this one. The 884-photo False Door's FeatureMatching takes about 43 s instead of 77-85 s, the match file the same bytes. The AMD packages carry one generic code object per RDNA family, GPU SIFT included, after the cause of PopSIFT's crash under a generic target was found (rocThrust's kernels are empty there; the grid filter now runs on the CPU, with the same features). In full: docs/releases/0.4.4.md.
v0.4.3 takes DepthMap's image uploads off the device-wide waits that HIP put in them: each cache slot is refilled in place on a stream of its own, the next batch's images go up during this batch's tiles, and a batch's load uploads each image as soon as it is decoded. The 884-photo False Door's DepthMap chunks take 1,142 s instead of 1,263 s, all 1,652 maps the same bytes. In full: docs/releases/0.4.3.md.
v0.4.2 takes DepthMap's GPU stages off double precision on AMD cards, exactly: the colour distances, the patch samples' projections and the colour optimisation's angles compute the same bits as before without FP64 instructions and an eleven-instruction division. The 884-photo False Door's DepthMap chunks take 1,297 s instead of 1,878 s, all 1,652 maps the same bytes. In full: docs/releases/0.4.2.md.
v0.4.1 gives the same output in half the time: the 884-photo False Door 10,930 s to 5,269 s, DepthMap 5,587 s to 1,733 s, with every change of ours byte-identical to the code it replaces. FeatureMatching uses the cards' integer dot-product units, SfMExpanding repeats itself on large sets, and AliceVision's two fixes from this project are in. The one output on the test sets that changes is Texturing's UV layout, by one of those fixes. In full: docs/releases/0.4.1.md.
v0.4.0 pairs upstream's new SfM pipeline on Meshroom 2025.1 (below). Meshroom ships it as Photogrammetry Experimental, and an AliceVision maintainer has said it replaces StructureFromMotion and PrepareDenseScene in the next release. Cheshire's SfM work is ported to its nodes: on 41 photos the Experimental graph's nodes take 357 s instead of 743 s with those nodes on Meshroom's own binaries, and SfMExpanding 29 s instead of 334 s. In full: docs/releases/0.4.0.md. v0.3.9 added the Photogrammetry Fast Ransac templates (notes).
v0.3.8 gave the same output sooner. At Meshroom 2025.1's RANSAC defaults, FeatureMatching's geometric filtering on 41 views takes 16.4 s instead of 36.8 s. StructureFromMotion reads features and colours faster, 307.8 s to 240.9 s on the 884-photo False Door. On a four-thread host, PrepareDenseScene compresses its EXRs with libdeflate and undistorts on the GPU, 38 % faster on an i3. Every one of these gives the output it gave before, to the bit. A race in PopSIFT's CUDA descriptor kernel is fixed, so NVIDIA runs now repeat exactly, as AMD runs already did. What changed, in full: docs/releases/0.3.8.md. v0.3.7 replaced Ceres in incremental SfM's bundle adjustment with Grin, Cheshire's own solver (notes).
There is nothing to pick any more. Until v0.2.17 there were six Windows downloads and choosing
the wrong one did not fail: a package built for one chip enumerates another, runs every kernel and
returns wrong data with no error at all. The bundle carries every payload and
cheshire-detect.exe asks the card which one it needs - the arch name the runtime reports, never a
table of PCI IDs, because a table needs an entry for hardware that does not exist yet. Run
cheshire-run.cmd --which to see what it chose (docs/16).
Three of the eleven targets have been run on a real card - gfx1012, gfx1031 and
gfx12-generic. Four more are the same architecture as a tested sibling (gfx1010, gfx1030, gfx1032,
gfx1034) and four are hardware nobody here owns (the three APUs and gfx11-generic). The APUs are
the row to watch: they are unified-memory parts, and the memory bridge was designed and measured
against a discrete card behind PCIe. If you run one, please say how it went. The eight are listed in
gpu/<family>/UNTESTED, and both cheshire-run.cmd and the Meshroom launcher announce it on every
run that selects one. The zips from v0.3.2 to v0.3.7 shipped without the list, and until v0.3.8 the
Meshroom launcher never read it.
The package carries every DLL it needs, the MSVC and OpenMP runtimes included (until 2026-09-15 it
did not, and a machine without Visual Studio died with exit code 0xC0000135 and no message). The
RDNA1/RDNA2 half is built /arch:AVX and runs on anything from Sandy Bridge and Bulldozer onwards;
the RDNA3/RDNA4 half is AVX2, so a pre-2013 CPU with a new card dies with 0xC000001D (illegal
instruction). The RDNA3/RDNA4 half also needs Adrenalin 26.2.2 or newer, since it carries the
HIP 7.2 runtime and a 2025 driver answers hipErrorNoDevice, shown by the tools as "No
CUDA-Enabled GPU" even though the card is fine. The RDNA1/RDNA2 half uses the runtime the driver
ships and has no such floor - and the probe tries them in that order, so a card the HIP 7 runtime
refuses simply falls through to the one that works.
Reproduce a row: unpack a cache under data/ref/<dataset>/, then scripts\run-depthmap.cmd <dataset>
(Windows, set CHESHIRE_INSTALL to the unzipped folder) or scripts/linux/run-depthmap.sh (Linux).
Both run the exact Meshroom 2023.3 DepthMap command line and finish with scripts/compare_depthmaps.py,
which prints the per-view table and writes the side-by-side panels. Photos are
alicevision/dataset_monstree.
Meshroom runs its DepthMap node as aliceVision_depthMapEstimation from its own aliceVision\bin.
meshroom-pair.cmd (in every Windows zip from v0.3.1 - the v0.3.0 CUDA zip shipped without it, take
it from this repository - and in
cheshire-meshroom-pair-windows.zip for
the older zips) replaces that one binary with a launcher and keeps the CUDA one beside it as
.cuda.exe:
meshroom-pair.cmd C:\Meshroom-2023.3.0 C:\cheshire-alicevision-windows-x64
meshroom-pair.cmd C:\Meshroom-2023.3.0 --unpair
Meshroom 2025.1 pairs the same way, from v0.3.6, on Windows and Linux (the 0.3.6 to 0.3.8 gates ran through it on every card and package). What to know:
- The DepthMap override: 2025.1 keeps its node descriptions as source in
aliceVision\share\meshroom\aliceVision. Pairing installs the 48-view DepthMap override there, keeping Meshroom's own file asDepthMap.py.meshroom.--unpairputs it back. meshroom_batch --cacheis ignored in 2025.1: the graph computes in the temp folder'sMeshroomCachewhatever you pass. Use--save <folder>\project.mg, and the cache is<folder>\MeshroomCache.- On Windows
meshroom_batch.exere-launches itself and exits at once while its copy computes. A script that waits for it should setALICEVISION_LIBPATHto the Meshroom folder'saliceVision\bin;aliceVision\lib;lib;<folder>first. See docs/04, "0.3.6: Meshroom 2025.1". - 2025.1 raised two RANSAC limits to 50000,
FeatureMatching:maxIteration(was 2048) andStructureFromMotion:localizerEstimatorMaxIterations(was 4096). On the engine bay and the 884-photo False Door that cost minutes of CPU matching for no more views placed. The paired nodes keep those defaults; from v0.3.9 pairing adds the Photogrammetry Fast Ransac and Photogrammetry Draft Fast Ransac templates (File > New Pipeline), Meshroom's own with the 2023.3 values set in the graph, and from v0.4.0 Photogrammetry Experimental Fast Ransac. On the RX 9070 box they took the 41-view graph from 378 s to 307 s, and FeatureMatching from 374 s to 117 s on the engine bay and from 30 minutes to 7.4 on the False Door, with the same views placed (docs/04, 0.3.9).--unpairremoves them. - The new SfM pipeline (from v0.4.0). 2025.1's Photogrammetry Experimental runs upstream's next pipeline: TracksBuilding, RelativePoseEstimating, SfMBootStrapping and SfMExpanding where StructureFromMotion was, IntrinsicsTransforming and ExportImages where PrepareDenseScene was. Pairing covers those eight nodes too, seventeen in all; Meshroom 2023.3, which has no such template, pairs nine as before. On 41 photos the Experimental graph's nodes took 357 s, against 743 s with those eight on Meshroom's own binaries (docs/04).
The launcher decides per run. When the package matches the card - a CUDA package and an NVIDIA card
that answers nvidia-smi, or an AMD package and no such card - it runs the build from the package,
with the package's DLLs and share/ in front so nothing of Meshroom's older AliceVision leaks in;
otherwise it runs Meshroom's own binary. CHESHIRE_BACKEND=auto|cheshire|meshroom forces one, and
CHESHIRE_DEPTHMAP=cuda|hip is the older spelling of the same switch, still honoured. The choice is
printed as the first line of the node's log. The nodes Cheshire does not carry - CameraInit,
MeshFiltering, Publish - keep running from Meshroom.
Until v0.3.7 auto meant Meshroom's own binary whenever an NVIDIA card answered, so a Cheshire
CUDA package from those releases never ran unless CHESHIRE_BACKEND=cheshire was set.
Given a bundle it also picks the payload for the card and prints that too
(bundle payload hip6.2/gfx1031), composing the layered PATH per run. A flat single-chip package
from an older release still works exactly as before - the shape is detected, not configured.
v0.2.17 and v0.2.18: the copy of
meshroom-pair.cmdinside those zips cannot pair the bundle. It looks for<package>\bin\aliceVision_depthMapEstimation.exe, which only a flat package has, and stops with "no HIP aliceVision_depthMapEstimation.exe". The launcher beside it has always understood both shapes; only the pairing script had not. v0.3.0 carries the fix; on an older zip, dropscripts/windows/meshroom-pair.cmdfrom this repository in beside the launcher.
From v0.2.13 the pairing also covers FeatureExtraction, so GPU SIFT reaches the graph: leave
forceCpuExtraction unticked (docs/14). With an older package, or one
for a card the HIP runtime cannot see, the node falls back to CPU SIFT without saying so — a
paired node that still logs [cpu] means the runtime cannot see the card, not that pairing
failed. If you are on a pre-v0.2.13 package, keep the option ticked. The same pairing on Linux is
scripts/linux/meshroom-pair.sh.
Both AMD packages carry RDNA3 code objects (Windows: gfx11-generic, which covers gfx1100-1103 and
gfx1150-1153; Linux: gfx1100/1101/1102 and the APUs gfx1103/1150/1151/1152/1153), and neither has run
on RDNA3 hardware; there is no such chip here. Ten minutes on an RX 7600/7700/7800/7900,
or a Ryzen 7040/8040/AI 300 laptop, closes the gap (Windows: if it
exits without a message, the exit code says why: 0xC0000135 means a DLL is missing, 0xC000001D
means the CPU lacks AVX2; "No CUDA-Enabled GPU" with the card present means the Adrenalin
driver predates 26.2.2):
- Clone this repository, and download the Windows zip (or the Linux AMD bundle) and
monstree-mini6-meshroom-cache.tar.gzfrom the release pages above. - Unpack the cache under
data/ref/monstree-mini6/, unzip the package anywhere, thenset CHESHIRE_INSTALL=<unzipped folder>andscripts\run-depthmap.cmd monstree-mini6(Linux:scripts/linux/run-depthmap.sh <bundle> <cache> <out> <cache>/DepthMap/<id>). The comparison at the end needs Python 3 withnumpyandOpenEXR(pip install numpy OpenEXR). - It prints the card name,
Task done in (s), and a per-view table against the CUDA reference;compare_stats.mdlands next to the depth maps. Open an issue with those two things and the card model. A[cheshire] bridge summaryline appears withCHESHIRE_BRIDGE_LOG=1if anything spilled.
Expected: mask agreement 1.000, median relative depth error 0.0000, 97-99 % of pixels within 1 % on every view, and a time somewhere between the RX 6750 XT and the RX 9070 rows.
The current plan is docs/roadmap.md, rebuilt on 2026-09-22 from every open item in the docs, the validation log and the code, each checked against the tree. The numbered list below is how the project got here; parts of it are out of date, and docs/roadmap.md lists which.
The aim is a small PC with a big GPU that runs a Meshroom job as fast as a workstation and just as precisely. In order, each timed on the 41-view and engine bay sets and checked against the CPU output - bit-identity where the same computation moved to another device, and equivalence at the reconstruction where it could not (SIFT is a different descriptor implementation, not the same kernels elsewhere):
DepthMapFilter on the GPU.Done in v0.2.6 (docs/08): 123.5 s to 26.5 s on the engine bay job, what remains is EXR reading; the shared decoded-map cache followed in v0.2.9.Meshing's voting pass.Done in v0.2.7 (docs/09): both ray-marching passes on the GPU, 37 s to 18 s on the engine bay job. It was not the majority of Meshing: the profile said the Boykov-Kolmogorov max-flow (144 s) and building its graph (63 s) were, followed by the dense point cloud (74 s), the neighbour tables (47 s) and the tetrahedralisation (41 s). The graph build, the tables and the kd-tree were then fixed on the CPU, exactly (docs/11), in v0.2.10 the max-flow itself moved to the GPU (docs/12): 109 s to 5.3 s, the same labelling, and the two visibility passes followed (docs/13): 56 s to 13 s, nanoflann's own tree walked on the device. The fusion went last, in v0.2.16, and again the name was misleading: "Load depth maps and add points" spent 60 % of its time in a gaussian blur, not loading anything - 108.7 of 180.8 thread-seconds against 65.5 for all three EXR reads. On the device it is 17.69 s to 3.06 s, reproducing OpenImageIO rather than approximating it, which needed the edge policy, the accumulation order and FMA contraction all matched (HIP defines__fmul_rnand__fadd_rnas the plain operators, so the compiler contracts them right back unless told not to). Meshing is 101 s; the visibility votes have since moved to the device as well (v0.3.5), and the tetrahedralisation stays on the CPU.Texturing.Done in v0.2.8 (docs/10): the per-camera Laplacian pyramid and rasterisation on the GPU, the camera selection parallel, images read ahead; 165.8 s to 79.3 s on the engine bay job. The UV unwrap followed in v0.2.16, on the CPU and byte-identical:ChartRect::insertwalked the whole tree for each of 69,565 charts because occupied leaves returnnullptrbut are still visited (6.28 s to 0.66 s, each node now carrying the largest free extent beneath it), andpackChartsbuilt 7,029,609 single-elementstd::vectors where one contiguous array of 12-byte PODs does (3.31 s to 1.90 s). Together 14.41 s to 8.56 s, and 51.9 s to 16.8 s on a 2011 Bulldozer - seven million allocations and an O(n^2) pointer chase punish a slow memory subsystem hardest. Padding and the save followed in v0.3.2, and the Lanczos downscale in v0.3.3, which this list once called not reproducible bit for bit on a GPU: with the tap weights computed on the host as OpenImageIO computes them and the sums in its order, 0 of 50,331,648 channels differ.FeatureExtraction (SIFT) on the GPU.Done in v0.2.13 (docs/14): PopSift built as HIP, 2021 s to 26 s on the 41-view set. This one is not bit-identical to the CPU and cannot be - it is a different descriptor implementation, not the same kernels on another device - so the test is the reconstruction: 88,463 landmarks against the CPU path's 78,372 at a lower reprojection error, and within 0.11 % of each other across RDNA1, RDNA2 and RDNA4 on two runtimes. Found an upstream bug on the way (popsift#193).Geometric verification on the GPU.Done in v0.2.15, on the CPU, and the profile is the whole story (docs/15). AC-RANSAC was 566 s of FeatureMatching's 644 s, so it looked like the next port. Measuring first put 48 % of it in onestd::sort- of(residual, index)pairs whose indices are read on 0.026 % of sorts - and only 8 % in the per-element virtual dispatch a code read had blamed. Sorting 8-byte keys with a radix on the double's bit pattern, and going straight to the error functor, gives 566 s -> 351 s with a byte-identical match file and identical iteration, sort and improved-model counts. The port is not planned: iterations are not independent (the sampling pool becomes the current inliers once a meaningful model appears), so the only parallelism is across pairs, and 111.7 M sequential iterations against a per-workgroup budget of about a microsecond make 2-3x a lot of device code for less than two functions bought.- The SVD in
Nullspace2, about 137 s of FeatureMatching and the largest single item left anywhere. Eigen'sJacobiSVDis solving a 9x9 for the fundamental matrix's null space when only the last two singular vectors are wanted. There is no free lunch in it: the two changes that would be byte-identical are already upstream, sinceNullspace/Nullspace2ask forComputeFullValone and the minimal solver already hands them a fixed-sizeMat9. Every cheaper route left (a fixed-iteration Jacobi,LDLTon the normal equations, inverse iteration) gives a different vector within rounding, so unlike everything above this one cannot be byte-identical and has to be argued on reconstruction quality instead. It shipped opt-in in v0.2.18 (CHESHIRE_QR_NULLSPACE=1: 1.86x on geometric filtering for 0.12 % fewer landmarks and 0.14 % more reprojection error, docs/17); the quality measurement has existed since v0.3.5, and QR stays opt-in. One Windows packageDone in v0.2.17 (docs/16): eleven payloads across both HIP runtimes in 181 MB, against 3,520 MB as one package per target, because only five DLLs carry GPU code - 4.7 MB per chip - and the vcpkg runtime andshare/tree are bit-identical across toolchains. It closed the gfx1010, gfx1034 and APU gaps, and RDNA3/RDNA4 collapsed togfx11-generic+gfx12-generic, which cover future chips in those families; RDNA1/RDNA2 cannot follow, because HIP SDK 6.2 emits generics only under a code-object version clang calls not production-ready. The probe runs each runtime family in its own process: loading a HIP runtime the installed driver does not support can exit 0xC0000005 rather than report no device, and only in a non-interactive session, which is how Meshroom runs a node. Still to do: x86-64 tiers (v1 / AVX / v3) for the Linux bundle, which is SSE2-only today, and the same generic collapse there - 19 hand-listed code objects become six, though Vega must stay explicit since it is wave64 where all of RDNA is wave32.A CUDA build of the same treeDone in v0.3.0 (docs/18) and packaged for both systems, PopSIFT and the memory bridge included; both NVIDIA packages have been gated on hardware in every release since v0.3.3. What remains is a Linux bundle built against an older glibc for Ubuntu 22.04 / Debian 12 nodes.- Hardware still unrun: RDNA3 discrete, the RDNA3.5 APUs, Vega, and a card without the 4-byte dot instruction (RX 5700, original Vega) for the matcher's fallback path.
Not planned: the tetrahedralisation, which would mean replacing geogram - that is also what stands between this and a byte-reproducible mesh, since geogram renumbers its cells from byte-identical input on every run. SfM was on this line until v0.3.7, on the grounds that Ceres' GPU solvers are CUDA-only and the outer loop dominates. Measured, bundle adjustment was most of it (63 % on the engine bay, 59 % on the 884-photo False Door), so Cheshire wrote its own solver, Grin, and rewrote the host code around it exactly; SfM now repeats itself byte for byte.
| Path | What |
|---|---|
hip/compat/include/cheshire/ |
the CUDA -> HIP compatibility header, the memory bridge, the mipmap emulation |
hip/port/ |
fused SGM aggregation and the other upstreamable source changes, applied by scripts/apply_hip_patch.py |
hip/tests/ |
standalone HIP probes: textures, surfaces, mipmaps, bandwidth, allocation, launch overhead, the bridge |
scripts/ |
Windows build (build-alicevision.cmd), Linux superbuild and bundle (scripts/linux/), validation runner, comparison tool |
docs/ |
findings, toolchain notes, bridge design, port log, validation, performance, Linux build |
third_party/aliceVision |
upstream AliceVision, pinned as a submodule and left untouched; the HIP backend is a patch set |
third_party/popsift |
upstream PopSift, cloned rather than vendored and patched by scripts/apply_popsift_patch.py; built as HIP by scripts/build-popsift.cmd (scripts/linux/build-popsift.sh) |
- Windows, one GPU target: docs/01-toolchain-windows.md, then
scripts\build-alicevision.cmd gfx1201 install. The one Windows package is composed from per-target payloads (scripts/build_targets.py <family> <targets>), the two families' base packages (scripts/package_windows.py) andscripts/bundle_windows.py(docs/16). - CUDA, Windows and Linux: docs/18-cuda-build.md.
- Linux (RDNA1-RDNA4): docs/06-linux-build.md, then
scripts/linux/build-deps.shandscripts/linux/build-alicevision.sh bundle. - Validate the numbers:
scripts\run-depthmap.cmd <dataset>orscripts/linux/run-depthmap.shagainst a Meshroom cache;scripts/compare_depthmaps.pyproduces the numbers and panels. - Validate the package, which is a different question and is checked separately, because a package
can be numerically perfect in six stages and broken in the seventh:
scripts/verify_bundle_stages.py <bundle> <cache>(HIP) andscripts\windows\verify-cuda-stages.ps1(CUDA) run every GPU-bearing stage from the package and require each one to print its own port's line, not merely to produce files.scripts/verify_end_to_end.py <meshroom> <package> <photos> <out>pairs the package into Meshroom and runs whole pipelines under several parameter sets, including one with everyCHESHIRE_GPU_*switch off, which has to fall back to the CPU and still finish.
Works end to end on RDNA1, RDNA2 and RDNA4 (Windows and Linux); RDNA3 has its code object in every bundle but no hardware run yet. GCN 4 (RX 400/500) is out: the ROCm 7.2 runtime refuses to initialise on an RX 570 even though the kernel driver accepts it (docs/06). From v0.3.0 the same stages are built for CUDA as well, on both systems.
A whole Meshroom graph, 2023.3 or 2025.1, runs on each gated package with all nine Cheshire nodes
paired, and on 2025.1, where seventeen are paired, Photogrammetry Experimental too.
scripts/verify_end_to_end.py checks it: every node it scores has to prove which binary ran and print
its own port's line, rather than merely produce a mesh, since a pipeline that fell back to Meshroom's
own binaries would produce a perfectly good one (ImageMatching's change is opt-in, so the gate does
not score it). The 0.4.1 release gate (2026-10-07, docs/04) ran the Windows AMD package as downloaded on
the RX 9070 through the 19-configuration mini6 matrix and the 41-view set on Meshroom 2025.1 and a mini6
check on 2023.3, 28 whole pipelines with v0.4.0's depth maps; the Linux packages are byte for byte the
builds the RX 6750 XT and a GTX 1080 Ti gated, the GTX also with every change since v0.4.0 switched off
against on, node by node. The Windows NVIDIA zip shipped on its build checks again, its box being down. A
legacy run scores eight nodes and a run of the new pipeline fourteen. Its verify and verifyexp runs
switch on every in-process self-check, the new pipeline's included, and each came out identical on every
card. The 0.4.0 gate before it ran 109 whole pipelines on four cards.
The gate's first runs, on 2026-09-20 (docs/04):
- the v0.3.0 Windows AMD bundle passed the stage gate 6/6 and five whole pipelines 5/5 on an
RX 9070, 6/6 ports each - including one with every
CHESHIRE_GPU_*switch off, which fell back to the CPU and still produced a textured mesh; - the Windows CUDA package passed the same two gates on a GTX 1050 Ti, 6/6 and 5/5;
- the Linux CUDA package, extracted from the release tarball rather than run from a build tree, produced a depth map byte-identical to the Meshroom CUDA 11.3 reference on a GTX 1080 Ti.
The same gate runs on Linux, and on 2026-09-20 the shipped v0.3.0 Linux HIP bundle passed all five
parameter sets on an RX 6750 XT (house-pc), 6/6 ports each - the first time the Linux AMD artifact
has been checked as a whole pipeline rather than stage by stage. Building that gate immediately
found that the Linux CUDA bundle never pairs GPU SIFT: it ships libpopsift.so.0.10.0 where the
pairing script looked for libpopsift.so, and the gate's own first pass missed it because
Meshroom's own featureExtraction is also a CUDA PopSIFT and prints the identical line. The gate now
requires each node to prove which binary ran before it looks at any port. What comes next is the
roadmap above.
Primary repository: git.hausofdub.com/dspl1236/Cheshire; mirror: github.com/dspl1236/Cheshire. Licensed MPL-2.0.