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"
|
async-trait = "0.1"
|
||||||
num_cpus = "1"
|
num_cpus = "1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
libloading = "0.8"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -217,4 +251,11 @@ mod tests {
|
|||||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
assert!(!features.has_ggml_baseline());
|
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