./run_dev.sh run --rm buildProduces build/libfoundation_pose_nvidia.so and build/foundation_pose_nvidia_cli.
docker/docker_build.sh resolves the target architectures in this order:
- An explicit
CUDA_ARCHITECTURESenv var (CMake format — e.g.120,native, or75;80;86) - The container-provided
CUDA_ARCH_LIST(e.g.7.5 8.0 8.6 9.0 10.0 12.0), auto-converted to CMake format — so the default container build supports every GPU the base image does - Fallback
120
For a faster single-arch build:
CUDA_ARCHITECTURES=120 ./run_dev.sh run --rm build # Blackwell
CUDA_ARCHITECTURES=86 ./run_dev.sh run --rm build # AmpereCompile jobs: BUILD_JOBS=<n> (default 4). Native (non-container) builds are
supported — see CMakeLists.txt.
The runtime ships two IRenderer implementations:
- Built-in CUDA rasterizer (default). Self-contained, part of
libfoundation_pose_nvidia.so, no extra dependencies or downloads. Used automatically — nothing to configure. - nvdiffrast (optional). Uses the CUDA rasterizer core of
NVlabs/nvdiffrast. nvdiffrast is
licensed under the NVIDIA Source Code License (separate from this
repository's Apache-2.0 code) and is disabled by default — it is not
fetched or built unless you explicitly enable it with
WITH_NVDIFFRAST=1/-DFOUNDATION_POSE_WITH_NVDIFFRAST=ON. It is packaged as its own dynamically loaded shared library,libfoundation_pose_nvdiffrast.so— the main library never contains or links nvdiffrast code.
# 1. Build the plugin (fetches nvdiffrast at a pinned, validated commit,
# applies the standalone-build patches, and produces
# build/libfoundation_pose_nvdiffrast.so next to the main library):
WITH_NVDIFFRAST=1 ./run_dev.sh run --rm build
# 2. Select it at runtime (per process; default remains the built-in rasterizer):
./run_dev.sh run --rm -e FP_RENDERER=nvdiffrast cli --smoke --mode register ...Native builds: configure with -DFOUNDATION_POSE_WITH_NVDIFFRAST=ON -DNVDIFFRAST_ROOT=/path/to/nvdiffrast. The plugin is loaded with dlopen
from the main library's directory ($ORIGIN) or LD_LIBRARY_PATH; if
FP_RENDERER=nvdiffrast is requested without the plugin present, estimator
creation fails with a clear error.
The build produces the shared library libfoundation_pose_nvidia.so plus the
public headers under include/foundation_pose_nvidia/; link the library (or load it
via FFI) and integrate through the C ABI in
c_api.h:
fp_default_config → fp_create (or fp_create_model_free) → fp_prepare →
fp_register_frame / fp_track_frame → fp_destroy; multi-object via
fp_group_*. Worked C and Python workflows are in
doc/ARCHITECTURE.md.
Buffer conventions: RGB HWC uint8, depth HW float32 in meters, mask
HW uint8 (non-zero = object), intrinsics 3×3 row-major float32 (host). Image
buffers may be host or CUDA device pointers — the location is auto-detected,
and device input skips the host-to-device copy. Each estimator handle owns its
own CUDA stream and GPU workspace; use one handle per object. TensorRT engine
precision is selectable per estimator via fp_config_t.tensorrt_precision
(TF32 default; strict FP32, FP16, BF16 — see fp_precision_t in c_api.h).
Engines are cached per precision.
The Python package (python/) layers a Pythonic
Estimator / RgbdFrame API (numpy or GPU tensors) over the same ABI
(precision via RuntimeConfig(tensorrt_precision=Precision.FP32)), and the
C++ API additionally accepts custom IRenderer / IInferenceRunner
backends (see doc/ARCHITECTURE.md).
run_dev.sh auto-detects aarch64 and transparently uses compose.thor.yaml — no
flags needed. All commands in the root README work unchanged on Thor.
- Jetson AGX Thor flashed with JetPack 7.0 GA / L4T R38
(verify:
head -1 /etc/nv_tegra_release→# R38 (release), REVISION: 2.0 ...). - Docker + NVIDIA Container Toolkit per the official Thor Docker Setup.
- Internet access on the board (to pull the base image and fetch nvdiffrast).
- FoundationPose ONNX weights — same Hugging Face source as x86.
- Everything runs inside
nvcr.io/nvidia/pytorch:26.05-py3(aarch64 variant).
compose.thor.yaml sets CUDA_ARCHITECTURES=native automatically so the Thor SM is
auto-detected (no need to override CUDA_ARCHITECTURES).
After building, verify CUDA is accessible inside the container:
./run_dev.sh run --rm --entrypoint python3 cli \
-c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
# expected: True ThorOn x86 you'd use gpus: all. On Thor that does not work, and even runtime: nvidia
alone leaves the container with no CUDA device (CUDA error 100).
Root cause: on JetPack 7 / L4T R38, libnvidia-container in auto mode mis-detects
Thor (it has both a Tegra release file and a dGPU-style driver), and the shipped
devices.csv lists the old Tegra node layout (/dev/nvgpu/igpu0/*,
/dev/nvhost-*-gpu) that does not exist on Thor. Thor's real iGPU nodes are:
/dev/nvidia0,/dev/nvidiactl,/dev/nvidia-modeset,/dev/nvmap/dev/nvgpu/igpu-<pci>/*/dev/nvgpu-pci/card-<pci>*
compose.thor.yaml therefore keeps runtime: nvidia (which still mounts the Tegra
driver libs via drivers.csv) and injects the real nodes explicitly via devices:,
device_cgroup_rules:, and bind-mounts of /dev/nvgpu + /dev/nvgpu-pci.
If you still hit
error 100: confirm the node paths on your board (ls /dev/nvidia* ; ls -R /dev/nvgpu /dev/nvgpu-pci) and adjust thedevices:/volumes:lists incompose.thor.yamlif your BSP revision names them differently.