use std::{future::Future, sync::Arc};
use crossbeam::channel::{self, Receiver};
use wgpu::Backends;
use floem_winit::window::{Window, WindowId};
pub struct GpuResources {
pub surface: wgpu::Surface<'static>,
pub adapter: wgpu::Adapter,
pub device: wgpu::Device,
pub queue: wgpu::Queue,
}
impl GpuResources {
pub fn request<F: Fn(WindowId) + 'static>(
on_result: F,
window: Arc<Window>,
) -> Receiver<Result<Self, GpuResourceError>> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::util::backend_bits_from_env().unwrap_or(Backends::all()),
..Default::default()
});
let (tx, rx) = channel::bounded(1);
spawn({
async move {
let surface = match instance.create_surface(Arc::clone(&window)) {
Ok(surface) => surface,
Err(err) => {
tx.send(Err(GpuResourceError::SurfaceCreationError(err)))
.unwrap();
on_result(window.id());
return;
}
};
let Some(adapter) = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: Some(&surface),
force_fallback_adapter: false,
})
.await
else {
tx.send(Err(GpuResourceError::AdapterNotFoundError))
.unwrap();
on_result(window.id());
return;
};
tx.send(
adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
..Default::default()
},
None,
)
.await
.map_err(GpuResourceError::DeviceRequestError)
.map(|(device, queue)| Self {
surface,
adapter,
device,
queue,
}),
)
.unwrap();
on_result(window.id());
}
});
rx
}
}
#[derive(Debug)]
pub enum GpuResourceError {
SurfaceCreationError(wgpu::CreateSurfaceError),
AdapterNotFoundError,
DeviceRequestError(wgpu::RequestDeviceError),
}
impl std::fmt::Display for GpuResourceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GpuResourceError::SurfaceCreationError(err) => {
write!(f, "Surface creation error: {}", err)
}
GpuResourceError::AdapterNotFoundError => {
write!(f, "Failed to find a suitable GPU adapter")
}
GpuResourceError::DeviceRequestError(err) => write!(f, "Device request error: {}", err),
}
}
}
pub fn spawn<F>(future: F)
where
F: Future<Output = ()> + 'static,
{
#[cfg(target_arch = "wasm32")]
wasm_bindgen_futures::spawn_local(future);
#[cfg(not(target_arch = "wasm32"))]
futures::executor::block_on(future)
}