use windows::{
core::Interface,
Win32::Graphics::Dxgi::{
CreateDXGIFactory1, DXGI_ADAPTER_DESC1, DXGI_MEMORY_SEGMENT_GROUP_LOCAL,
DXGI_QUERY_VIDEO_MEMORY_INFO, IDXGIAdapter1, IDXGIAdapter3, IDXGIFactory1,
},
};
use super::GpuEntry;
use crate::metrics::push_history;
const INTEL_VENDOR_ID: u32 = 0x8086;
pub fn refresh(gpus: &mut Vec<GpuEntry>) -> bool {
let factory: IDXGIFactory1 = match unsafe { CreateDXGIFactory1::<IDXGIFactory1>() } {
Ok(f) => f,
Err(_) => return false,
};
let mut candidates: Vec<(String, Option<IDXGIAdapter3>)> = Vec::new();
let mut i = 0u32;
loop {
let adapter: IDXGIAdapter1 = match unsafe { factory.EnumAdapters1(i) } {
Ok(a) => a,
Err(_) => break,
};
i += 1;
let desc: DXGI_ADAPTER_DESC1 = match unsafe { adapter.GetDesc1() } {
Ok(d) => d,
Err(_) => continue,
};
if (desc.Flags & 2) != 0 {
continue;
}
if desc.VendorId != INTEL_VENDOR_ID {
continue;
}
let end = desc.Description.iter().position(|&c| c == 0).unwrap_or(128);
let name = String::from_utf16_lossy(&desc.Description[..end]);
let adapter3: Option<IDXGIAdapter3> = adapter.cast::<IDXGIAdapter3>().ok();
candidates.push((name, adapter3));
}
if candidates.is_empty() {
return false;
}
if gpus.len() != candidates.len() {
*gpus = candidates
.iter()
.map(|(name, _)| GpuEntry::new(name.clone()))
.collect();
}
for (idx, (_, adapter3)) in candidates.iter().enumerate() {
let (mem_used, mem_total) = adapter3
.as_ref()
.map(query_vram)
.unwrap_or((0, 0));
let gpu = &mut gpus[idx];
gpu.utilization = 0.0;
gpu.mem_used = mem_used;
gpu.mem_total = mem_total;
gpu.mem_is_gtt = false;
gpu.temperature = None;
gpu.power_watts = None;
push_history(&mut gpu.util_history, 0.0);
let mem_pct = if mem_total > 0 {
mem_used as f32 / mem_total as f32 * 100.0
} else {
0.0
};
push_history(&mut gpu.mem_history, mem_pct);
}
true
}
fn query_vram(adapter: &IDXGIAdapter3) -> (u64, u64) {
let mut info = DXGI_QUERY_VIDEO_MEMORY_INFO::default();
let ok = unsafe {
adapter
.QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &mut info)
.is_ok()
};
if ok {
(info.CurrentUsage, info.Budget)
} else {
(0, 0)
}
}