Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,43 @@ jobs:
- name: Run cargo test with SIMD
run: cargo test --workspace --features simd

# M9-3 (#142): proves the pure-Rust default builds and tests cleanly
# WITHOUT a C++ toolchain installed. Pinned to ubuntu-latest because the
# invariant we're testing is build-system gating (build.rs only runs the
# FreakMatcher C++ compilation when `--features ffi-backend` is set), not
# platform-specific compilation. Critically, this job does NOT install
# libclang-dev — if any unconditional bindgen/cc dependency ever leaks
# into the no-features build path, this job fails.
pure-rust-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# Submodules deliberately NOT recursive — the pure-Rust path must
# never touch the WebARKitLib C++ source tree.

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Rust Cache
uses: Swatinem/rust-cache@v2

- name: Run cargo fmt check (pure-Rust)
run: cargo fmt --all -- --check

- name: Run cargo check (no features)
run: cargo check -p webarkitlib-rs

- name: Run cargo clippy (no features)
run: cargo clippy -p webarkitlib-rs -- -D warnings

- name: Run cargo build (no features)
run: cargo build -p webarkitlib-rs

- name: Run cargo test (no features)
run: cargo test -p webarkitlib-rs

kpm-build:
strategy:
fail-fast: false
Expand Down
26 changes: 22 additions & 4 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ The unified core library containing all AR functionality:
- **KPM module** (`kpm`): Keypoint Matching subsystem (FREAK descriptor-based tracking):
- `kpm::handle` — high-level KPM handle and matching orchestration.
- `kpm::backend` — pluggable feature-extraction backend trait and error types.
- `kpm::cpp_backend` — C++ FreakMatcher FFI backend (feature-gated: `ffi-backend`).
- `kpm::rust_backend` — **default** pure-Rust `FreakMatcher` backend (M9-2, #141). Used by `cargo build` out of the box; no C++ compiler required.
- `kpm::cpp_backend` — opt-in C++ FreakMatcher FFI backend (feature-gated: `--features ffi-backend`). Available for validation, regression testing, and `DualFreakMatcher` cross-checks.
- `kpm::matching` — per-frame matching and ICP-based pose estimation.
- `kpm::ref_data_set` — `.fset3` reference data I/O and compression modes.
- `kpm::types` — KPM data structures and constants.
Expand All @@ -53,11 +54,12 @@ Depends only on `webarkitlib-rs` (the core crate).

| Feature | Description |
|----------------|-------------|
| **(default)** | **Empty** — the pure-Rust `FreakMatcher` is the default backend (M9-3, #142). No C++ compiler required. |
| `simd` | Umbrella: enables all SIMD sub-features |
| `simd-wasm32` | WASM SIMD128 intrinsics |
| `simd-x86-sse41` | x86 SSE4.1 intrinsics |
| `log-helpers` | Enable logging infrastructure (installs `env_logger` for desktop/tests, `console_log` for WASM) |
| `ffi-backend` | Compile the C++ FreakMatcher library and generate FFI bindings |
| `ffi-backend` | **Opt-in** — compile the C++ FreakMatcher library and generate FFI bindings. Used for cross-validation and the regression-test suite; not required for production tracking. |
| `dual-mode` | Enables FFI-based parity tests that validate pure-Rust ports against the live C++ baseline (M6 math/solvers/homography, M7 BHC/matcher, PRNG). Transitively enables `ffi-backend`. Run in CI on Linux/macOS/Windows. |

## SIMD Strategy
Expand All @@ -75,13 +77,29 @@ Performance-critical functions are optimized using SIMD. The strategy involves:

## Building and Testing

### Native
### Pure Rust tracking (default — no C++ compiler needed)

Since **M9-3 (#142)**, a plain `cargo build` uses the pure-Rust
`FreakMatcher` and requires no C++ toolchain. The `ffi-backend`
compilation is fully gated behind the opt-in `--features ffi-backend`
flag in `crates/core/build.rs`.

```bash
# No clang / libclang / cc required — pure Rust end-to-end.
cargo build -p webarkitlib-rs
cargo test -p webarkitlib-rs

# Production tracking with SIMD acceleration:
cargo build --release --features simd
cargo test --workspace --features simd
```

### With C++ FFI backend
The C++ FreakMatcher (`CppFreakMatcher`) is now an opt-in development
tool used for validation, regression testing, and cross-stack parity
gates — not a runtime dependency for production NFT tracking.

### Opt-in: C++ FFI backend (validation / regression suite)

```bash
# Bootstrap C++ sources first (one-time setup)
cd benchmarks/c_benchmark && python ../bootstrap.py --bootstrap-file libraries.json && cd ../..
Expand Down
46 changes: 43 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,43 @@ Add `webarkitlib-rs` to your `Cargo.toml`:
webarkitlib-rs = "0.6"
```

To enable the C++ FFI backend for KPM (Natural Feature Tracking):
### Pure Rust tracking (no C++ compiler required)

Since **M9-3 (#142)**, the default backend is the pure-Rust
`FreakMatcher`. A plain `cargo add webarkitlib-rs` (or the snippet
above) gives you a fully functional NFT/KPM tracker with **no C++
toolchain, libclang, or `cc` required at build time**:

```bash
cargo build # works on machines without clang/libclang/cc
cargo test
```

The whole `crates/core/build.rs` `FreakMatcher` C++ compilation path
is gated behind `cfg!(feature = "ffi-backend")` — opt-in only.

### Building without C++

If you are integrating WebARKitLib-rs from a containerized environment
or any host that doesn't have a C++ toolchain installed, you don't
need to do anything special:

```toml
[dependencies]
webarkitlib-rs = "0.6" # default backend is pure Rust
```

```bash
cargo build # succeeds without a C++ compiler installed
```

### Opt-in: C++ FFI backend (for validation only)

The C++ `FreakMatcher` is still available as an opt-in backend, used
internally for cross-validation (`--features dual-mode`), regression
testing (`kpm_regression`), and the cross-stack parity gate
(`cross_stack_parity`). It is **no longer required for production
NFT tracking**:

```toml
[dependencies]
Expand Down Expand Up @@ -85,7 +121,11 @@ This example loads a camera parameter file, a marker (pattern or barcode), and a
Generate NFT (Natural Feature Tracking) marker files compatible with ARnft and NFT-Marker-Creator-App:

```bash
# Basic usage (requires C++ FREAK backend for .fset3):
# nft_marker_gen still requires --features ffi-backend (M9-3 #142):
# it uses CppFreakMatcher to generate .fset3 files, which is the
# legacy C++ NFT-marker-creator behaviour. Runtime tracking with
# pre-built .fset3 files works on the pure-Rust default — only
# marker generation needs the C++ FREAK extractor here.
cargo run --release --features ffi-backend --example nft_marker_gen -- \
--input path/to/image.jpg \
--output path/to/output_name \
Expand Down Expand Up @@ -120,7 +160,7 @@ This produces three files:

| Feature flag | What it enables |
|---|---|
| `ffi-backend` | C++ FREAK backend for `.fset3` generation (required for full NFT markers) |
| `ffi-backend` | C++ FREAK backend (opt-in since M9-3 #142). Required only for legacy `.fset3` generation in `nft_marker_gen` and for development cross-validation. Runtime NFT tracking with existing `.fset3` files works on the pure-Rust default. |
| `simd-x86-sse41` | SSE4.1 SIMD acceleration for feature map correlation (`get_similarity`) |
| `simd-x86-avx2` | AVX2+FMA SIMD acceleration for feature map correlation (faster than SSE4.1) |
| `simd` | Umbrella flag — enables all SIMD optimizations (SSE4.1, AVX2, WASM SIMD, image, pattern) |
Expand Down
11 changes: 10 additions & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ cc = "1"
bindgen = "0.72.1"

[features]
# Default features intentionally empty (M9-3, #142): a plain `cargo build`
# uses the pure-Rust FreakMatcher and requires no C++ compiler. The C++
# FFI backend is opt-in via `--features ffi-backend` for validation /
# regression testing.
default = []
simd = ["simd-image", "simd-pattern", "simd-wasm32", "simd-x86-sse41", "simd-x86-avx2"]
simd-image = []
simd-pattern = []
Expand Down Expand Up @@ -107,7 +112,11 @@ required-features = ["log-helpers"]

[[example]]
name = "nft_marker_gen"
required-features = ["log-helpers"]
# M9-3 #142: this example uses `CppFreakMatcher` directly, so it requires
# `ffi-backend` in addition to `log-helpers`. (Pre-M9-3 it built only
# because the FFI backend was always available; with the pure-Rust default,
# it must explicitly opt in.)
required-features = ["log-helpers", "ffi-backend"]

[[example]]
name = "barcode"
Expand Down
35 changes: 34 additions & 1 deletion crates/core/benches/BENCHMARKS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# WebARKitLib.rs Core Benchmarks

**Last Updated**: 2026-03-11 15:37:20 (UTC+1)
**Last Updated**: 2026-06-04 (M9-3 — #142)

This document tracks the performance of critical image processing and pattern matching functions in the `webarkitlib_rs` core crate.

Expand Down Expand Up @@ -45,3 +45,36 @@ cargo bench --bench simd_bench
- **Target OS**: Windows
- **Target Architecture**: x86_64 (SSE4.1)
- **Frame Size**: 640x480 (typical AR video resolution)

## KPM / NFT performance (M9-3 status)

Issue #142's acceptance criterion calls for the pure-Rust NFT pipeline
to run within 20% of the C++ backend on `pinball-demo`. As of M9-3,
**there is no dedicated benchmark exercising the KPM / FreakMatcher
path**. The existing `marker_bench` measures `ar_detect_marker`
(barcode/template marker detection), which doesn't touch the
FreakMatcher and therefore can't distinguish pure-Rust from the C++
FFI backend.

### Functional parity evidence (in lieu of wall-clock numbers)

The Rust and C++ backends agree on the meaningful outputs across
several test suites:

| Test | What it asserts | Status post-#170 |
|------|------------------|------------------|
| `test_dual_mode_no_divergence_on_pinball` | M9 #152 tier-2: `max_corner_displacement < 2.0 px` between C++ and Rust homographies on `found.jpg/img.jpg` | ✅ zero divergences |
| `absolute_corner_error` (#166 Track A) | Each backend's max corner-error against hand-annotated ground truth stays within baseline + 3.5 px epsilon | ✅ green; **Rust is more accurate than C++** on `pinball-demo` (Rust 5.27 px vs C++ 18.79 px) |
| `cross_stack_parity` (jsartoolkitNFT#584 Track 2) | C++ FFI and Rust pose agree with jsartoolkitNFT-Node within rot 0.08 / trans 10 mm | ✅ green |
| `kpm_regression::test_full_pipeline_pose` | Linux C++ pose matches committed numerical baseline to 1e-2 | ✅ green |

The within-20% perf target is treated as **deferred, not failed**:
the functional evidence shows Rust meets parity by every quality
metric we measure, and #142 explicitly permits deferring the
quantitative perf check to a follow-up: *"If slower, open a follow-up
performance issue rather than blocking this PR."*

A future PR will add a KPM-specific Criterion bench (`kpm_bench.rs`)
that loads `pinball.fset3` + `pinball-demo.jpg` and times
`kpm_matching` with each backend, producing the dedicated wall-clock
comparison.
Loading