use anyhow::{Context, Result};
use std::sync::Arc;
#[derive(Clone)]
pub struct GpuDevice {
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpuState {
Available,
Unavailable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpuType {
Discrete,
Integrated,
Unknown,
}
impl GpuDevice {
pub fn new() -> Result<Self> {
pollster::block_on(async {
let instance = wgpu::Instance::default();
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: None,
force_fallback_adapter: false,
})
.await
.context("Failed to find a suitable GPU adapter")?;
let info = adapter.get_info();
let gpu_type = Self::classify_gpu_type(&info);
println!("🎮 GPU Device: {} ({:?})", info.name, info.backend);
println!(" Driver: {} / {}", info.driver, info.driver_info);
println!(" Type: {:?}", gpu_type);
if gpu_type == GpuType::Integrated {
println!(" ⚠️ Integrated GPU detected - may be slower than CPU synthesis");
println!(" 💡 Tip: GPU acceleration works best with discrete graphics cards");
}
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: Some("Tunes GPU Synthesizer"),
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::default(),
memory_hints: wgpu::MemoryHints::Performance,
},
None,
)
.await
.context("Failed to create GPU device")?;
Ok(Self {
device: Arc::new(device),
queue: Arc::new(queue),
})
})
}
pub fn state(&self) -> GpuState {
GpuState::Available
}
pub fn supports_compute(&self) -> bool {
true
}
fn classify_gpu_type(info: &wgpu::AdapterInfo) -> GpuType {
let name_lower = info.name.to_lowercase();
if name_lower.contains("intel")
&& (name_lower.contains("hd graphics")
|| name_lower.contains("uhd graphics")
|| name_lower.contains("iris")
|| name_lower.contains("integrated"))
{
return GpuType::Integrated;
}
if name_lower.contains("amd")
&& (name_lower.contains("radeon(tm) graphics")
|| name_lower.contains("vega") && !name_lower.contains("rx"))
{
return GpuType::Integrated;
}
if name_lower.contains("nvidia")
|| name_lower.contains("geforce")
|| name_lower.contains("rtx")
|| name_lower.contains("gtx")
{
return GpuType::Discrete;
}
if name_lower.contains("amd")
&& (name_lower.contains("radeon rx")
|| name_lower.contains("radeon r9")
|| name_lower.contains("radeon r7"))
{
return GpuType::Discrete;
}
GpuType::Unknown
}
}
impl std::fmt::Debug for GpuDevice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GpuDevice")
.field("state", &self.state())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gpu_initialization() {
match GpuDevice::new() {
Ok(device) => {
println!("GPU initialized successfully: {:?}", device);
assert_eq!(device.state(), GpuState::Available);
assert!(device.supports_compute());
}
Err(e) => {
println!("GPU not available (expected on some systems): {}", e);
}
}
}
}