use super::{Backend, BackendCapabilities, BackendType};
use crate::{GpuDevice, Result};
pub struct VulkanBackend {
capabilities: BackendCapabilities,
device: Option<GpuDevice>,
}
impl VulkanBackend {
pub fn new() -> Result<Self> {
let device = GpuDevice::new(None)?;
let capabilities = Self::query_capabilities(&device);
Ok(Self {
capabilities,
device: Some(device),
})
}
fn query_capabilities(device: &GpuDevice) -> BackendCapabilities {
let info = device.info();
let backend_type = match info.backend.as_str() {
"Vulkan" => BackendType::Vulkan,
"Metal" => BackendType::Metal,
"DirectX 12" => BackendType::DX12,
_ => BackendType::Vulkan, };
BackendCapabilities {
backend_type,
max_workgroup_size: (256, 256, 64),
max_workgroup_invocations: 256,
max_buffer_size: 1024 * 1024 * 1024, compute_shaders: true,
subgroups: false,
push_constants: false,
}
}
#[must_use]
pub fn device(&self) -> Option<&GpuDevice> {
self.device.as_ref()
}
#[must_use]
pub fn is_vulkan(&self) -> bool {
matches!(self.capabilities.backend_type, BackendType::Vulkan)
}
#[must_use]
pub fn device_info(&self) -> Option<String> {
self.device.as_ref().map(|d| {
let info = d.info();
format!("{} ({}) - {}", info.name, info.device_type, info.backend)
})
}
}
impl Backend for VulkanBackend {
fn capabilities(&self) -> &BackendCapabilities {
&self.capabilities
}
fn is_available() -> bool {
GpuDevice::new(None).is_ok()
}
fn initialize() -> Result<Self> {
Self::new()
}
}
impl Default for VulkanBackend {
fn default() -> Self {
match Self::new() {
Ok(backend) => backend,
Err(e) => panic!("Failed to initialize Vulkan backend: {e}"),
}
}
}
pub struct VulkanFeatures {
pub descriptor_indexing: bool,
pub buffer_device_address: bool,
pub subgroup_operations: bool,
pub ray_tracing: bool,
}
impl VulkanFeatures {
#[must_use]
pub fn query() -> Self {
Self {
descriptor_indexing: false,
buffer_device_address: false,
subgroup_operations: false,
ray_tracing: false,
}
}
#[must_use]
pub fn has_advanced_features(&self) -> bool {
self.descriptor_indexing
|| self.buffer_device_address
|| self.subgroup_operations
|| self.ray_tracing
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore] fn test_vulkan_backend_available() {
let available = VulkanBackend::is_available();
println!("Vulkan available: {available}");
}
#[test]
fn test_vulkan_features() {
let features = VulkanFeatures::query();
println!("Vulkan features: {:?}", features.has_advanced_features());
}
}