Amp-Thread-ID: https://ampcode.com/threads/T-01a0b2dd-db32-712d-99ce-12ce4a86d979 Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
92 lines
3.0 KiB
Rust
92 lines
3.0 KiB
Rust
pub struct Wgpu {
|
|
_instance: wgpu::Instance,
|
|
pub surface: wgpu::Surface<'static>,
|
|
pub device: wgpu::Device,
|
|
pub queue: wgpu::Queue,
|
|
pub config: wgpu::SurfaceConfiguration,
|
|
pub format: wgpu::TextureFormat,
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub timestamp_queries: bool,
|
|
/// Optional features the device was created with, in WebGPU spelling.
|
|
pub features: Vec<&'static str>,
|
|
pub adapter: String,
|
|
}
|
|
|
|
const OPTIONAL_FEATURES: [(wgpu::Features, &str); 2] = [
|
|
(wgpu::Features::TIMESTAMP_QUERY, "timestamp-query"),
|
|
(
|
|
wgpu::Features::INDIRECT_FIRST_INSTANCE,
|
|
"indirect-first-instance",
|
|
),
|
|
];
|
|
|
|
impl Wgpu {
|
|
pub async fn new(canvas: web_sys::OffscreenCanvas) -> Result<Self, String> {
|
|
let width = canvas.width();
|
|
let height = canvas.height();
|
|
if width == 0 || height == 0 {
|
|
return Err("CANVAS_SIZE".into());
|
|
}
|
|
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
|
|
backends: wgpu::Backends::BROWSER_WEBGPU,
|
|
..Default::default()
|
|
});
|
|
let surface = instance
|
|
.create_surface(wgpu::SurfaceTarget::OffscreenCanvas(canvas))
|
|
.map_err(|_| "SURFACE")?;
|
|
let adapter = instance
|
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
|
compatible_surface: Some(&surface),
|
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
force_fallback_adapter: false,
|
|
})
|
|
.await
|
|
.map_err(|_| "WEBGPU_UNAVAILABLE")?;
|
|
let required_features = OPTIONAL_FEATURES
|
|
.iter()
|
|
.fold(wgpu::Features::empty(), |features, (feature, _)| {
|
|
features | *feature
|
|
})
|
|
& adapter.features();
|
|
let info = adapter.get_info();
|
|
let adapter_name = if info.name.is_empty() {
|
|
format!("{:?} · {:?}", info.device_type, info.backend)
|
|
} else {
|
|
format!(
|
|
"{} · {:?} · {:?}",
|
|
info.name, info.device_type, info.backend
|
|
)
|
|
};
|
|
let (device, queue) = adapter
|
|
.request_device(&wgpu::DeviceDescriptor {
|
|
required_features,
|
|
..Default::default()
|
|
})
|
|
.await
|
|
.map_err(|_| "DEVICE")?;
|
|
let config = surface
|
|
.get_default_config(&adapter, width, height)
|
|
.ok_or("SURFACE")?;
|
|
let format = config.format;
|
|
surface.configure(&device, &config);
|
|
Ok(Self {
|
|
_instance: instance,
|
|
surface,
|
|
device,
|
|
queue,
|
|
config,
|
|
format,
|
|
width,
|
|
height,
|
|
timestamp_queries: required_features.contains(wgpu::Features::TIMESTAMP_QUERY),
|
|
features: OPTIONAL_FEATURES
|
|
.iter()
|
|
.filter(|(feature, _)| required_features.contains(*feature))
|
|
.map(|(_, name)| *name)
|
|
.collect(),
|
|
adapter: adapter_name,
|
|
})
|
|
}
|
|
}
|