use log::info;
use serde::Serialize;
use std::ffi::CStr;
use whisper_rs::whisper_rs_sys;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum GpuKind {
Dedicated,
Integrated,
}
#[derive(Debug, Clone, Serialize)]
pub struct GpuDeviceInfo {
pub id: i32,
pub name: String,
pub kind: GpuKind,
pub total_vram: usize,
pub free_vram: usize,
}
pub fn list_gpu_devices() -> Vec<GpuDeviceInfo> {
let type_gpu = whisper_rs_sys::ggml_backend_dev_type_GGML_BACKEND_DEVICE_TYPE_GPU as i32;
let type_igpu = whisper_rs_sys::ggml_backend_dev_type_GGML_BACKEND_DEVICE_TYPE_IGPU as i32;
unsafe {
let count = whisper_rs_sys::ggml_backend_dev_count();
let mut gpu_devices = Vec::new();
let mut gpu_index: i32 = 0;
for i in 0..count {
let dev = whisper_rs_sys::ggml_backend_dev_get(i);
if dev.is_null() {
continue;
}
let dev_type = whisper_rs_sys::ggml_backend_dev_type(dev) as i32;
if dev_type != type_gpu && dev_type != type_igpu {
continue;
}
let name = {
let ptr = whisper_rs_sys::ggml_backend_dev_description(dev);
if ptr.is_null() {
format!("GPU {gpu_index}")
} else {
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
};
let mut free: usize = 0;
let mut total: usize = 0;
whisper_rs_sys::ggml_backend_dev_memory(dev, &mut free, &mut total);
let kind = if dev_type == type_gpu {
GpuKind::Dedicated
} else {
GpuKind::Integrated
};
gpu_devices.push(GpuDeviceInfo {
id: gpu_index,
name,
kind,
total_vram: total,
free_vram: free,
});
gpu_index += 1;
}
gpu_devices
}
}
pub fn auto_select_gpu_device() -> i32 {
let devices = list_gpu_devices();
if devices.is_empty() {
return 0;
}
let best = devices
.iter()
.max_by_key(|d| {
let kind_priority = match d.kind {
GpuKind::Dedicated => 1u8,
GpuKind::Integrated => 0,
};
(kind_priority, d.total_vram)
})
.unwrap();
info!(
"Auto-selected GPU device {} '{}' ({:?}, {} MB VRAM)",
best.id,
best.name,
best.kind,
best.total_vram / (1024 * 1024),
);
best.id
}