Skip to content
dspl1236Public

About

Meshroom/AliceVision photogrammetry on AMD Radeon GPUs via HIP: CUDA->HIP compatibility layer, VRAM->system-RAM memory bridge, Windows + Linux bundles, validated on RDNA1/2/4 against a CUDA node.

Topics

Resources

Stars

7 stars

Watchers

2 watching

Forks

Repository files navigation

Cheshire

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.

What it does today

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).

Why there is an NVIDIA build (v0.3.0)

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.

Results

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).

What "identical" means here, per comparison

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).

Memory bridge

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.

GPU descriptor matcher (2026-09-16)

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.

Full-resolution depth maps under a cap (downscale 1, 41 views, 2026-09-16)

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.

What was found on the way (reproducers in hip/tests/)

  • HIP drops surf2Dwrite stores 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 hipMallocMipmappedArray on 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 ten v_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 of useConsistentScale fall 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, atomicMin into default (fine-grained) host memory fails on every element while atomicAdd works, and both are right on hipHostMallocNonCoherent memory (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.exe with clang for HIP: use clang-cl for both. -fgpu-rdc is 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/dxg flavour of libhsa-runtime64, which must be swapped for the KFD one. With those in place RDNA1 works natively on ROCm 7.2.

Downloads

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.

Using it from Meshroom on Windows

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 as DepthMap.py.meshroom. --unpair puts it back.
  • meshroom_batch --cache is ignored in 2025.1: the graph computes in the temp folder's MeshroomCache whatever you pass. Use --save <folder>\project.mg, and the cache is <folder>\MeshroomCache.
  • On Windows meshroom_batch.exe re-launches itself and exits at once while its copy computes. A script that waits for it should set ALICEVISION_LIBPATH to the Meshroom folder's aliceVision\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) and StructureFromMotion: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). --unpair removes 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.cmd inside 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, drop scripts/windows/meshroom-pair.cmd from 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.

Help wanted: RDNA3

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):

  1. Clone this repository, and download the Windows zip (or the Linux AMD bundle) and monstree-mini6-meshroom-cache.tar.gz from the release pages above.
  2. Unpack the cache under data/ref/monstree-mini6/, unzip the package anywhere, then set CHESHIRE_INSTALL=<unzipped folder> and scripts\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 with numpy and OpenEXR (pip install numpy OpenEXR).
  3. It prints the card name, Task done in (s), and a per-view table against the CUDA reference; compare_stats.md lands next to the depth maps. Open an issue with those two things and the card model. A [cheshire] bridge summary line appears with CHESHIRE_BRIDGE_LOG=1 if 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.

Roadmap

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):

  1. 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.
  2. 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_rn and __fadd_rn as 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.
  3. 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::insert walked the whole tree for each of 69,565 charts because occupied leaves return nullptr but are still visited (6.28 s to 0.66 s, each node now carrying the largest free extent beneath it), and packCharts built 7,029,609 single-element std::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.
  4. 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).
  5. 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 one std::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.
  6. The SVD in Nullspace2, about 137 s of FeatureMatching and the largest single item left anywhere. Eigen's JacobiSVD is 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, since Nullspace/Nullspace2 ask for ComputeFullV alone and the minimal solver already hands them a fixed-size Mat9. Every cheaper route left (a fixed-iteration Jacobi, LDLT on 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.
  7. One Windows package Done 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 and share/ tree are bit-identical across toolchains. It closed the gfx1010, gfx1034 and APU gaps, and RDNA3/RDNA4 collapsed to gfx11-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.
  8. A CUDA build of the same tree Done 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.
  9. 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.

Layout

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)

Building

  • 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) and scripts/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.sh and scripts/linux/build-alicevision.sh bundle.
  • Validate the numbers: scripts\run-depthmap.cmd <dataset> or scripts/linux/run-depthmap.sh against a Meshroom cache; scripts/compare_depthmaps.py produces 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) and scripts\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 every CHESHIRE_GPU_* switch off, which has to fall back to the CPU and still finish.

Status

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.

About

Meshroom/AliceVision photogrammetry on AMD Radeon GPUs via HIP: CUDA->HIP compatibility layer, VRAM->system-RAM memory bridge, Windows + Linux bundles, validated on RDNA1/2/4 against a CUDA node.

Topics

Resources

Stars

7 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages