use windows::Win32::Graphics::Dxgi::{
CreateDXGIFactory1, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, DXGI_QUERY_VIDEO_MEMORY_INFO,
IDXGIAdapter, IDXGIAdapter3, IDXGIFactory1,
};
use windows::core::Interface;
const NVIDIA_VENDOR_ID: u32 = 0x10DE;
pub(super) struct DxgiQueryResult {
pub current_usage: u64,
pub dedicated_video_memory: u64,
pub adapter_name: Option<String>,
}
#[allow(unsafe_code)]
pub(super) fn query(idx: u32) -> Option<DxgiQueryResult> {
let factory: IDXGIFactory1 = unsafe { CreateDXGIFactory1() }.ok()?;
let mut raw_idx: u32 = 0;
let mut nvidia_count: u32 = 0;
loop {
let adapter1 = unsafe { factory.EnumAdapters1(raw_idx) }.ok()?;
let adapter: IDXGIAdapter = adapter1.cast().ok()?;
let desc = unsafe { adapter.GetDesc() }.ok()?;
if desc.VendorId == NVIDIA_VENDOR_ID && desc.DedicatedVideoMemory > 0 {
if nvidia_count == idx {
#[allow(clippy::as_conversions)]
let total = desc.DedicatedVideoMemory as u64;
let raw_name = String::from_utf16_lossy(&desc.Description);
let trimmed = raw_name.trim_end_matches('\0');
let adapter_name = if trimmed.is_empty() {
None
} else {
Some(trimmed.to_owned())
};
let adapter3: IDXGIAdapter3 = adapter.cast().ok()?;
let mut mem_info = DXGI_QUERY_VIDEO_MEMORY_INFO::default();
unsafe {
adapter3.QueryVideoMemoryInfo(
0,
DXGI_MEMORY_SEGMENT_GROUP_LOCAL,
&raw mut mem_info,
)
}
.ok()?;
#[cfg(feature = "debug-output")]
eprintln!(
"[DXGI debug] adapter[nvidia#{idx} raw#{raw_idx}]: name={adapter_name:?}, \
dedicated_vram={total}, current_usage={}, budget={}",
mem_info.CurrentUsage, mem_info.Budget
);
return Some(DxgiQueryResult {
current_usage: mem_info.CurrentUsage,
dedicated_video_memory: total,
adapter_name,
});
}
nvidia_count += 1;
}
raw_idx += 1;
}
}
#[allow(unsafe_code)]
pub(super) fn adapter_name(idx: u32) -> Option<String> {
let factory: IDXGIFactory1 = unsafe { CreateDXGIFactory1() }.ok()?;
let mut raw_idx: u32 = 0;
let mut nvidia_count: u32 = 0;
loop {
let adapter1 = unsafe { factory.EnumAdapters1(raw_idx) }.ok()?;
let adapter: IDXGIAdapter = adapter1.cast().ok()?;
let desc = unsafe { adapter.GetDesc() }.ok()?;
if desc.VendorId == NVIDIA_VENDOR_ID && desc.DedicatedVideoMemory > 0 {
if nvidia_count == idx {
let raw_name = String::from_utf16_lossy(&desc.Description);
let trimmed = raw_name.trim_end_matches('\0');
return if trimmed.is_empty() {
None
} else {
Some(trimmed.to_owned())
};
}
nvidia_count += 1;
}
raw_idx += 1;
}
}
#[allow(unsafe_code)]
pub(super) fn device_count() -> Option<u32> {
let factory: IDXGIFactory1 = unsafe { CreateDXGIFactory1() }.ok()?;
let mut raw_idx: u32 = 0;
let mut count: u32 = 0;
loop {
let Ok(adapter1) = (unsafe { factory.EnumAdapters1(raw_idx) }) else {
break;
};
let Ok(adapter) = adapter1.cast::<IDXGIAdapter>() else {
break;
};
let Ok(desc) = (unsafe { adapter.GetDesc() }) else {
break;
};
if desc.VendorId == NVIDIA_VENDOR_ID && desc.DedicatedVideoMemory > 0 {
count += 1;
}
raw_idx += 1;
}
#[cfg(feature = "debug-output")]
eprintln!("[DXGI debug] device_count = {count} (NVIDIA adapters with non-zero VRAM)");
Some(count)
}