#![cfg(all(feature = "par", feature = "gpu-wgpu"))]
use alloc::sync::Arc;
#[cfg(feature = "std")]
use std::sync::Mutex;
use wgpu::{Device, Instance, Queue};
use super::error::{GpuError, GpuResult};
use super::kernel::KernelCache;
pub struct GpuWgpu {
device: Arc<Device>,
queue: Arc<Queue>,
min_len: usize,
kernel_cache: Arc<Mutex<KernelCache>>,
}
impl GpuWgpu {
#[inline]
pub fn new() -> GpuResult<Self> {
Self::with_min_len(1024)
}
pub fn with_min_len(min_len: usize) -> GpuResult<Self> {
let instance = Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
let adapter = super::block_on::block_on(
instance.request_adapter(&wgpu::RequestAdapterOptions::default()),
)
.map_err(|_| GpuError::AdapterNotFound)?;
let downlevel_capabilities = adapter.get_downlevel_capabilities();
if !downlevel_capabilities
.flags
.contains(wgpu::DownlevelFlags::COMPUTE_SHADERS)
{
return Err(GpuError::ComputeNotSupported);
}
let (device, queue) =
super::block_on::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
memory_hints: wgpu::MemoryHints::default(),
experimental_features: wgpu::ExperimentalFeatures::default(),
trace: wgpu::Trace::default(),
}))
.map_err(|e| GpuError::DeviceCreationFailed(alloc::format!("{e:?}")))?;
let device_arc: Arc<Device> = Arc::new(device);
Ok(Self {
kernel_cache: Arc::new(Mutex::new(KernelCache::new(Arc::clone(&device_arc)))),
device: device_arc,
queue: Arc::new(queue),
min_len,
})
}
#[inline]
pub fn device(&self) -> &Device {
&self.device
}
#[inline]
pub fn queue(&self) -> &Queue {
&self.queue
}
#[inline]
pub fn min_len(&self) -> usize {
self.min_len
}
#[inline]
pub(crate) fn kernel_cache(&self) -> &Arc<Mutex<KernelCache>> {
&self.kernel_cache
}
}
impl Default for GpuWgpu {
fn default() -> Self {
Self::new().expect("Failed to create GPU backend. Ensure a GPU is available and wgpu can find a suitable adapter.")
}
}