feat(core): port vulkan_loader_available from src-tauri

Adds libloading = "0.8" to magnotia-core dependencies and moves
vulkan_loader_available() into magnotia-core::hardware so non-Tauri
crates (transcription, llm) can probe the Vulkan loader without
depending on the Tauri binary. Test asserts the call completes on any
host regardless of whether libvulkan is installed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jars
2026-05-09 12:02:39 +01:00
parent 9c85c25b7f
commit b991355cb0
2 changed files with 42 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ sysinfo = "0.35"
async-trait = "0.1"
num_cpus = "1"
tracing = "0.1"
libloading = "0.8"
[dev-dependencies]
tempfile = "3"

View File

@@ -169,6 +169,40 @@ pub fn probe_system() -> SystemProfile {
}
}
/// Best-effort probe for the Vulkan loader shared library.
///
/// whisper.cpp and llama.cpp Vulkan backends silently drop to CPU if
/// `libvulkan.so.1` (Linux) / `vulkan-1.dll` (Windows) / the MoltenVK
/// bundle (macOS) is missing at runtime. We probe via
/// `libloading::Library::new`; a successful open means the loader is
/// resolvable and we should treat the GPU path as live.
///
/// Moved from `src-tauri/src/commands/models.rs` so non-Tauri crates
/// (transcription, llm) can call it without depending on the Tauri
/// binary.
pub fn vulkan_loader_available() -> bool {
#[cfg(target_os = "linux")]
let candidates: &[&str] = &["libvulkan.so.1", "libvulkan.so"];
#[cfg(target_os = "windows")]
let candidates: &[&str] = &["vulkan-1.dll"];
#[cfg(target_os = "macos")]
let candidates: &[&str] = &["libvulkan.1.dylib", "libMoltenVK.dylib"];
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
let candidates: &[&str] = &[];
for name in candidates {
// SAFETY: libloading::Library::new loads a shared library and
// returns a handle that is dropped at the end of this
// iteration. We do not call any symbols, so the open-for-probe
// pattern is sound.
match unsafe { libloading::Library::new(*name) } {
Ok(_lib) => return true,
Err(_) => continue,
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
@@ -217,4 +251,11 @@ mod tests {
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
assert!(!features.has_ggml_baseline());
}
#[test]
fn vulkan_loader_available_does_not_panic() {
// We can't assert the value (depends on host's libvulkan),
// but we can assert the call completes.
let _ = vulkan_loader_available();
}
}