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:
@@ -12,6 +12,7 @@ sysinfo = "0.35"
|
||||
async-trait = "0.1"
|
||||
num_cpus = "1"
|
||||
tracing = "0.1"
|
||||
libloading = "0.8"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user