Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit f9cf506

Browse files
authored
Merge pull request #227 from gn64/feature/vulkan_device_list
Add Vulkan GPU enumeration support (related to #160)
2 parents 1491bd6 + dac152c commit f9cf506

File tree

4 files changed

+89
-2
lines changed

4 files changed

+89
-2
lines changed

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#![allow(clippy::uninlined_format_args)]
22
#![cfg_attr(test, feature(test))]
33

4+
#[cfg(feature = "vulkan")]
5+
pub mod vulkan;
6+
47
mod common_logging;
58
mod error;
69
mod ggml_logging_hook;

src/vulkan.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use std::{ffi::CStr, os::raw::c_int};
2+
use whisper_rs_sys::{
3+
ggml_backend_buffer_type_t, ggml_backend_vk_buffer_type, ggml_backend_vk_get_device_count,
4+
ggml_backend_vk_get_device_description, ggml_backend_vk_get_device_memory,
5+
};
6+
7+
#[derive(Debug, Clone)]
8+
pub struct VKVram {
9+
pub free: usize,
10+
pub total: usize,
11+
}
12+
13+
/// Human-readable device information
14+
#[derive(Debug, Clone)]
15+
pub struct VkDeviceInfo {
16+
pub id: i32,
17+
pub name: String,
18+
pub vram: VKVram,
19+
/// Buffer type to pass to `whisper::Backend::create_buffer`
20+
pub buf_type: ggml_backend_buffer_type_t,
21+
}
22+
/// Enumerate every physical GPU ggml can see.
23+
///
24+
/// Note: integrated GPUs are returned *after* discrete ones,
25+
/// mirroring ggml’s C logic.
26+
pub fn list_devices() -> Vec<VkDeviceInfo> {
27+
unsafe {
28+
let n = ggml_backend_vk_get_device_count();
29+
(0..n)
30+
.map(|id| {
31+
// 256 bytes is plenty (spec says 128 is enough)
32+
let mut tmp = [0i8; 256];
33+
ggml_backend_vk_get_device_description(id as c_int, tmp.as_mut_ptr(), tmp.len());
34+
let mut free = 0usize;
35+
let mut total = 0usize;
36+
ggml_backend_vk_get_device_memory(id, &mut free, &mut total);
37+
VkDeviceInfo {
38+
id,
39+
name: CStr::from_ptr(tmp.as_ptr()).to_string_lossy().into_owned(),
40+
vram: VKVram { free, total },
41+
buf_type: ggml_backend_vk_buffer_type(id as usize),
42+
}
43+
})
44+
.collect()
45+
}
46+
}
47+
48+
#[cfg(test)]
49+
mod vulkan_tests {
50+
use super::*;
51+
52+
#[test]
53+
fn enumerate_must_not_panic() {
54+
let _ = list_devices();
55+
}
56+
57+
#[test]
58+
fn sane_device_info() {
59+
let gpus = list_devices();
60+
let mut seen = std::collections::HashSet::new();
61+
62+
for dev in &gpus {
63+
assert!(seen.insert(dev.id), "duplicated id {}", dev.id);
64+
assert!(!dev.name.trim().is_empty(), "GPU {} has empty name", dev.id);
65+
assert!(
66+
dev.vram.total >= dev.vram.free,
67+
"GPU {} total < free",
68+
dev.id
69+
);
70+
}
71+
}
72+
}

sys/build.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,18 @@ fn main() {
119119
let _: u64 = std::fs::copy("src/bindings.rs", out.join("bindings.rs"))
120120
.expect("Failed to copy bindings.rs");
121121
} else {
122-
let bindings = bindgen::Builder::default().header("wrapper.h");
122+
let mut bindings = bindgen::Builder::default().header("wrapper.h");
123123

124124
#[cfg(feature = "metal")]
125-
let bindings = bindings.header("whisper.cpp/ggml/include/ggml-metal.h");
125+
{
126+
bindings = bindings.header("whisper.cpp/ggml/include/ggml-metal.h");
127+
}
128+
#[cfg(feature = "vulkan")]
129+
{
130+
bindings = bindings
131+
.header("whisper.cpp/ggml/include/ggml-vulkan.h")
132+
.clang_arg("-DGGML_USE_VULKAN=1");
133+
}
126134

127135
let bindings = bindings
128136
.clang_arg("-I./whisper.cpp/")

sys/wrapper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
#include <include/whisper.h>
22
#include <ggml/include/ggml.h>
3+
4+
#ifdef GGML_USE_VULKAN
5+
#include "ggml-vulkan.h"
6+
#endif

0 commit comments

Comments
 (0)