renderling/internal/
cpu.rs1use std::sync::Arc;
3
4use snafu::{OptionExt, ResultExt};
5
6use crate::context::{
7 CannotCreateAdaptorSnafu, CannotRequestDeviceSnafu, ContextError, IncompatibleSurfaceSnafu,
8 RenderTarget, RenderTargetInner,
9};
10
11pub async fn adapter(
13 instance: &wgpu::Instance,
14 compatible_surface: Option<&wgpu::Surface<'_>>,
15) -> Result<wgpu::Adapter, ContextError> {
16 log::trace!(
17 "creating adapter for a {} context",
18 if compatible_surface.is_none() {
19 "headless"
20 } else {
21 "surface-based"
22 }
23 );
24 let adapter = instance
25 .request_adapter(&wgpu::RequestAdapterOptions {
26 power_preference: wgpu::PowerPreference::default(),
27 compatible_surface,
28 force_fallback_adapter: false,
29 })
30 .await
31 .context(CannotCreateAdaptorSnafu)?;
32
33 log::info!("Adapter selected: {:?}", adapter.get_info());
34 let info = adapter.get_info();
35 log::info!(
36 "using adapter: '{}' backend:{:?} driver:'{}'",
37 info.name,
38 info.backend,
39 info.driver
40 );
41 Ok(adapter)
42}
43
44pub async fn device(
46 adapter: &wgpu::Adapter,
47) -> Result<(wgpu::Device, wgpu::Queue), wgpu::RequestDeviceError> {
48 let wanted_features = wgpu::Features::INDIRECT_FIRST_INSTANCE
49 | wgpu::Features::MULTI_DRAW_INDIRECT
50 | wgpu::Features::VERTEX_WRITABLE_STORAGE
55 | wgpu::Features::CLEAR_TEXTURE;
56 let supported_features = adapter.features();
57 let required_features = wanted_features.intersection(supported_features);
58 let unsupported_features = wanted_features.difference(supported_features);
59 if !unsupported_features.is_empty() {
60 log::error!("requested but unsupported features: {unsupported_features:#?}");
61 log::warn!("requested and supported features: {supported_features:#?}");
62 }
63 let limits = adapter.limits();
64 log::info!("adapter limits: {limits:#?}");
65 adapter
66 .request_device(&wgpu::DeviceDescriptor {
67 required_features,
68 required_limits: adapter.limits(),
69 label: None,
70 memory_hints: wgpu::MemoryHints::default(),
71 trace: wgpu::Trace::Off,
72 })
73 .await
74}
75
76pub fn new_instance(backends: Option<wgpu::Backends>) -> wgpu::Instance {
81 log::info!(
82 "creating instance - available backends: {:#?}",
83 wgpu::Instance::enabled_backend_features()
84 );
85 let backends = backends.unwrap_or(wgpu::Backends::PRIMARY);
87 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
88 backends,
89 ..Default::default()
90 });
91
92 #[cfg(not(target_arch = "wasm32"))]
93 {
94 let adapters = instance.enumerate_adapters(backends);
95 log::trace!("available adapters: {adapters:#?}");
96 }
97
98 instance
99}
100
101pub async fn new_windowed_adapter_device_queue(
106 width: u32,
107 height: u32,
108 instance: &wgpu::Instance,
109 window: impl Into<wgpu::SurfaceTarget<'static>>,
110) -> Result<(wgpu::Adapter, wgpu::Device, wgpu::Queue, RenderTarget), ContextError> {
111 let surface = instance
112 .create_surface(window)
113 .map_err(|e| ContextError::CreateSurface { source: e })?;
114 let adapter = adapter(instance, Some(&surface)).await?;
115 let surface_caps = surface.get_capabilities(&adapter);
116 let fmt = if surface_caps
117 .formats
118 .contains(&wgpu::TextureFormat::Rgba8UnormSrgb)
119 {
120 wgpu::TextureFormat::Rgba8UnormSrgb
121 } else {
122 surface_caps
123 .formats
124 .iter()
125 .copied()
126 .find(|f| f.is_srgb())
127 .unwrap_or(surface_caps.formats[0])
128 };
129 let view_fmts = if fmt.is_srgb() {
130 vec![]
131 } else {
132 vec![fmt.add_srgb_suffix()]
133 };
134 log::info!("surface capabilities: {surface_caps:#?}");
135 let mut surface_config = surface
136 .get_default_config(&adapter, width, height)
137 .context(IncompatibleSurfaceSnafu)?;
138 surface_config.view_formats = view_fmts;
139 let (device, queue) = device(&adapter).await.context(CannotRequestDeviceSnafu)?;
140 surface.configure(&device, &surface_config);
141 let target = RenderTarget(RenderTargetInner::Surface {
142 surface,
143 surface_config,
144 });
145 Ok((adapter, device, queue, target))
146}
147
148pub async fn new_headless_device_queue_and_target(
153 width: u32,
154 height: u32,
155 instance: &wgpu::Instance,
156) -> Result<(wgpu::Adapter, wgpu::Device, wgpu::Queue, RenderTarget), ContextError> {
157 let adapter = adapter(instance, None).await?;
158 let texture_desc = wgpu::TextureDescriptor {
159 size: wgpu::Extent3d {
160 width,
161 height,
162 depth_or_array_layers: 1,
163 },
164 mip_level_count: 1,
165 sample_count: 1,
166 dimension: wgpu::TextureDimension::D2,
167 format: wgpu::TextureFormat::Rgba8UnormSrgb,
168 usage: wgpu::TextureUsages::COPY_SRC
169 | wgpu::TextureUsages::RENDER_ATTACHMENT
170 | wgpu::TextureUsages::TEXTURE_BINDING,
171 label: None,
172 view_formats: &[],
173 };
174 let (device, queue) = device(&adapter).await.context(CannotRequestDeviceSnafu)?;
175 let texture = Arc::new(device.create_texture(&texture_desc));
176 let target = RenderTarget(RenderTargetInner::Texture { texture });
177 Ok((adapter, device, queue, target))
178}