Probe and compile for a package's models, not only the user's
Benchmarks / CPU and I/O (per commit) (push) Failing after 6m30s
Benchmarks / Frame budget (on demand) (push) Skipped
Build and test / Desktop (Linux) (push) Failing after 53s
Build and test / Layer separation (push) Successful in 26s
Traceability / Requirement traces (push) Failing after 40s
🐳 Android image / Build and push (push) Successful in 1s
Build and test / android-image (push) Successful in 1s
🐳 Windows image / Build and push (push) Successful in 1s
Build and test / windows-image (push) Successful in 1s
Build and test / Android (aarch64) (push) Failing after 2m19s
Build and test / Windows (x86_64, cross) (push) Failing after 3m5s

`inference::init` listed the models from the user's shared directory
alone, while the app loads them from there or from the package's
`/usr/share/darkroom/models`. On a fresh package install the probe found
"no model to probe with", stayed on the CPU, and compiled nothing. Both
now resolve each file with the same search, `library::shared_model`.

The PKGBUILD names the ONNX Runtime packages as optional dependencies,
since the app loads one from /usr/lib if present.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-20 19:39:05 +02:00
co-authored by Claude Opus 5
parent 39a22875b1
commit 8a90d888d5
3 changed files with 43 additions and 25 deletions
+6 -1
View File
@@ -16,8 +16,13 @@ license=('GPL-3.0-or-later')
# Nextcloud credentials (FR-NC-2) — gnome-keyring or kwallet both provide it.
depends=('vulkan-icd-loader' 'fontconfig' 'libxkbcommon')
makedepends=('cargo' 'git')
# ONNX Runtime is loaded from /usr/lib at launch if a package put it there
# (docs/inference.md §3): the CPU build is 8–10× the built-in tract, the
# ROCm build adds the MIGraphX rung on an AMD GPU. Neither is required.
optdepends=('gnome-keyring: store Nextcloud credentials'
'kwallet: store Nextcloud credentials')
'kwallet: store Nextcloud credentials'
'onnxruntime-cpu: run the neural models on every core'
'onnxruntime-rocm: run the neural models on an AMD GPU')
options=('!lto') # the workspace sets its own LTO in Cargo.toml
_repo="$(cd "${startdir}/.." && pwd)"
+24 -20
View File
@@ -19,23 +19,26 @@ use dr_types::FaceDetector;
/// fingerprints the model files and a probe before they land would be a
/// probe of nothing.
pub fn init(runtime_dirs: Vec<PathBuf>) {
let dir = crate::library::shared_face_models_dir();
let mut models: Vec<(Role, PathBuf)> = FaceDetector::ALL
// Each file where the app will actually load it from — the user's
// shared directory, else the package's — so a fresh install with models
// only under `/usr/share` probes and compiles for them rather than
// finding nothing and settling on the CPU.
let mut wanted: Vec<(Role, &str)> = FaceDetector::ALL
.iter()
.map(|d| (Role::Detector, dir.join(d.file_name())))
.map(|d| (Role::Detector, d.file_name()))
.collect();
wanted.extend([
(Role::Embedder, "arcface_mbf_b1.onnx"),
(Role::Scene, "yolo26s-sem-ade20k.onnx"),
(Role::Landmarks, crate::library::LANDMARK_MODEL),
(Role::EyeClassifier, crate::library::EYE_MODEL),
(Role::EyeClassifier, crate::library::SUNGLASSES_MODEL),
(Role::Inpainter, crate::library::INPAINT_MODEL),
]);
let models: Vec<(Role, PathBuf)> = wanted
.into_iter()
.filter_map(|(role, name)| Some((role, crate::library::shared_model(name)?)))
.collect();
models.push((Role::Embedder, dir.join("arcface_mbf_b1.onnx")));
models.push((Role::Scene, dir.join("yolo26s-sem-ade20k.onnx")));
models.push((Role::Landmarks, dir.join(crate::library::LANDMARK_MODEL)));
models.push((Role::EyeClassifier, dir.join(crate::library::EYE_MODEL)));
models.push((
Role::EyeClassifier,
dir.join(crate::library::SUNGLASSES_MODEL),
));
if let Some(p) = crate::library::inpaint_model() {
models.push((Role::Inpainter, p));
}
models.retain(|(_, p)| p.is_file());
dr_inference_engine::init(dr_inference_engine::Config {
runtime_dirs,
@@ -75,12 +78,13 @@ pub fn user_runtime_dir() -> PathBuf {
/// Which form the current backend loads `detector` in, given the files on
/// this device — the fact `faces.model_id` has to carry (§7).
///
/// Reads the shared directory only. An account-private model directory can
/// override the file `library::face_models` loads, but not which form the
/// backend wants, and the int8 sibling is something a packager ships, not
/// something a user drops in.
/// Reads the shared and system directories only. An account-private model
/// directory can override the file `library::face_models` loads, but not
/// which form the backend wants, and the int8 sibling is something a
/// packager ships, not something a user drops in.
pub fn detector_form(detector: FaceDetector) -> Form {
let canonical = crate::library::shared_face_models_dir().join(detector.file_name());
let canonical = crate::library::shared_model(detector.file_name())
.unwrap_or_else(|| crate::library::shared_face_models_dir().join(detector.file_name()));
dr_inference_engine::resolve_model(Role::Detector, &canonical).1
}
+13 -4
View File
@@ -4463,6 +4463,18 @@ fn system_face_models_dirs() -> Vec<PathBuf> {
.collect()
}
/// The file `name` in the shared user models directory, else in the first
/// system directory that has it — the search every account-independent
/// model lookup makes, and the one the inference engine is told about, so
/// that a package's models under `/usr/share` are probed and compiled for
/// exactly as a user's own would be.
pub fn shared_model(name: &str) -> Option<PathBuf> {
std::iter::once(shared_face_models_dir())
.chain(system_face_models_dirs())
.map(|d| d.join(name))
.find(|p| p.is_file())
}
/// TRACES: FR-MRG-4
/// The panorama border filler, as shipped in `models/inpaint/`.
pub const INPAINT_MODEL: &str = "migan-512.onnx";
@@ -4473,10 +4485,7 @@ pub const INPAINT_MODEL: &str = "migan-512.onnx";
/// the per-account step, because a fill is not identity-bearing and no
/// library has a reason to pin its own.
pub fn inpaint_model() -> Option<PathBuf> {
std::iter::once(shared_face_models_dir())
.chain(system_face_models_dirs())
.map(|d| d.join(INPAINT_MODEL))
.find(|p| p.is_file())
shared_model(INPAINT_MODEL)
}
/// One grid cell's data, read from the catalog.