use std::ffi::CStr;
use std::ptr::addr_of_mut;
use tracing::{debug, info, warn};
use memonitor_sys::vulkan;
use crate::{
BackendHandle, BackendId, DeviceHandle, DeviceKind, GPUKind, MemoryStats, VULKAN_NAME,
};
pub(super) struct Vulkan {
handle: vulkan::Devices,
}
unsafe impl Send for Vulkan {}
unsafe impl Sync for Vulkan {}
impl Vulkan {
pub(super) fn init() -> Option<(Self, Vec<VulkanDevice>)> {
debug!("Attempting to load Vulkan monitor");
let res = unsafe { vulkan::init() };
if res == 0 {
let mut c_devices = unsafe { vulkan::list_devices() };
if c_devices.handle.is_null() {
warn!("No Vulkan devices found. Aborting Vulkan initialisation.");
unsafe { vulkan::term() };
return None;
}
let mut devices = Vec::with_capacity(c_devices.count as usize);
for i in 0..c_devices.count {
let c_device = unsafe { vulkan::get_device(addr_of_mut!(c_devices), i) };
if c_device.handle.is_null() {
warn!("Invalid device handle. Aborting Vulkan initialisation.");
unsafe {
vulkan::destroy_devices(addr_of_mut!(c_devices));
vulkan::term();
};
return None;
}
let properties = unsafe { vulkan::device_properties(c_device) };
if properties.name[0] == 0 {
warn!("Invalid device name. Aborting Vulkan initialisation.");
unsafe {
vulkan::destroy_devices(addr_of_mut!(c_devices));
vulkan::term();
};
return None;
}
if properties.total_memory == 0 {
warn!("Invalid amount of memory. Skipping this device.");
continue;
}
let name = unsafe { CStr::from_ptr(properties.name.as_ptr()) };
let kind = match properties.kind {
vulkan::DeviceKind::IntegratedGPU => DeviceKind::GPU(GPUKind::Integrated),
vulkan::DeviceKind::DiscreteGPU => DeviceKind::GPU(GPUKind::Discrete),
vulkan::DeviceKind::VirtualGPU => DeviceKind::GPU(GPUKind::Virtual),
vulkan::DeviceKind::CPU => DeviceKind::CPU,
vulkan::DeviceKind::Other => DeviceKind::Other,
_ => DeviceKind::Other,
};
let device = VulkanDevice {
handle: c_device,
name: name.to_string_lossy().to_string(),
kind,
memory: properties.total_memory,
};
devices.push(device);
}
let backend = Vulkan { handle: c_devices };
info!("Successfully initialised Vulkan backend.");
Some((backend, devices))
} else {
warn!("Vulkan runtime not found.");
None
}
}
}
impl BackendHandle for Vulkan {
fn name(&self) -> &str {
VULKAN_NAME
}
fn id(&self) -> BackendId {
BackendId::Vulkan
}
}
impl Drop for Vulkan {
fn drop(&mut self) {
unsafe {
vulkan::destroy_devices(addr_of_mut!(self.handle));
vulkan::term();
}
}
}
pub(super) struct VulkanDevice {
handle: vulkan::DeviceRef,
name: String,
kind: DeviceKind,
memory: usize,
}
unsafe impl Send for VulkanDevice {}
unsafe impl Sync for VulkanDevice {}
impl DeviceHandle for VulkanDevice {
fn name(&self) -> &str {
&self.name
}
fn kind(&self) -> DeviceKind {
self.kind
}
fn backend(&self) -> BackendId {
BackendId::Vulkan
}
fn current_memory_stats(&self) -> MemoryStats {
let c_stats = unsafe { vulkan::device_memory_properties(self.handle) };
let available_memory = c_stats.budget - c_stats.used;
MemoryStats {
total: self.memory,
available: available_memory,
used: self.memory - available_memory,
}
}
}