wgpu/api/adapter.rs
1use std::{future::Future, sync::Arc, thread};
2
3use crate::context::{DeviceRequest, DynContext};
4use crate::*;
5
6/// Handle to a physical graphics and/or compute device.
7///
8/// Adapters can be created using [`Instance::request_adapter`]
9/// or other [`Instance`] methods.
10///
11/// Adapters can be used to open a connection to the corresponding [`Device`]
12/// on the host system by using [`Adapter::request_device`].
13///
14/// Does not have to be kept alive.
15///
16/// Corresponds to [WebGPU `GPUAdapter`](https://gpuweb.github.io/gpuweb/#gpu-adapter).
17#[derive(Debug)]
18pub struct Adapter {
19 pub(crate) context: Arc<C>,
20 pub(crate) data: Box<Data>,
21}
22#[cfg(send_sync)]
23static_assertions::assert_impl_all!(Adapter: Send, Sync);
24
25impl Drop for Adapter {
26 fn drop(&mut self) {
27 if !thread::panicking() {
28 self.context.adapter_drop(self.data.as_ref())
29 }
30 }
31}
32
33pub use wgt::RequestAdapterOptions as RequestAdapterOptionsBase;
34/// Additional information required when requesting an adapter.
35///
36/// For use with [`Instance::request_adapter`].
37///
38/// Corresponds to [WebGPU `GPURequestAdapterOptions`](
39/// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions).
40pub type RequestAdapterOptions<'a, 'b> = RequestAdapterOptionsBase<&'a Surface<'b>>;
41#[cfg(send_sync)]
42static_assertions::assert_impl_all!(RequestAdapterOptions<'_, '_>: Send, Sync);
43
44impl Adapter {
45 /// Requests a connection to a physical device, creating a logical device.
46 ///
47 /// Returns the [`Device`] together with a [`Queue`] that executes command buffers.
48 ///
49 /// [Per the WebGPU specification], an [`Adapter`] may only be used once to create a device.
50 /// If another device is wanted, call [`Instance::request_adapter()`] again to get a fresh
51 /// [`Adapter`].
52 /// However, `wgpu` does not currently enforce this restriction.
53 ///
54 /// # Arguments
55 ///
56 /// - `desc` - Description of the features and limits requested from the given device.
57 /// - `trace_path` - Can be used for API call tracing, if that feature is
58 /// enabled in `wgpu-core`.
59 ///
60 /// # Panics
61 ///
62 /// - `request_device()` was already called on this `Adapter`.
63 /// - Features specified by `desc` are not supported by this adapter.
64 /// - Unsafe features were requested but not enabled when requesting the adapter.
65 /// - Limits requested exceed the values provided by the adapter.
66 /// - Adapter does not support all features wgpu requires to safely operate.
67 ///
68 /// [Per the WebGPU specification]: https://www.w3.org/TR/webgpu/#dom-gpuadapter-requestdevice
69 pub fn request_device(
70 &self,
71 desc: &DeviceDescriptor<'_>,
72 trace_path: Option<&std::path::Path>,
73 ) -> impl Future<Output = Result<(Device, Queue), RequestDeviceError>> + WasmNotSend {
74 let context = Arc::clone(&self.context);
75 let device = DynContext::adapter_request_device(
76 &*self.context,
77 self.data.as_ref(),
78 desc,
79 trace_path,
80 );
81 async move {
82 device.await.map(
83 |DeviceRequest {
84 device_data,
85 queue_data,
86 }| {
87 (
88 Device {
89 context: Arc::clone(&context),
90 data: device_data,
91 },
92 Queue {
93 context,
94 data: queue_data,
95 },
96 )
97 },
98 )
99 }
100 }
101
102 /// Create a wgpu [`Device`] and [`Queue`] from a wgpu-hal `OpenDevice`
103 ///
104 /// # Safety
105 ///
106 /// - `hal_device` must be created from this adapter internal handle.
107 /// - `desc.features` must be a subset of `hal_device` features.
108 #[cfg(wgpu_core)]
109 pub unsafe fn create_device_from_hal<A: wgc::hal_api::HalApi>(
110 &self,
111 hal_device: hal::OpenDevice<A>,
112 desc: &DeviceDescriptor<'_>,
113 trace_path: Option<&std::path::Path>,
114 ) -> Result<(Device, Queue), RequestDeviceError> {
115 let context = Arc::clone(&self.context);
116 unsafe {
117 self.context
118 .as_any()
119 .downcast_ref::<crate::backend::ContextWgpuCore>()
120 // Part of the safety requirements is that the device was generated from the same adapter.
121 // Therefore, unwrap is fine here since only WgpuCoreContext based adapters have the ability to create hal devices.
122 .unwrap()
123 .create_device_from_hal(
124 crate::context::downcast_ref(self.data.as_ref()),
125 hal_device,
126 desc,
127 trace_path,
128 )
129 }
130 .map(|(device, queue)| {
131 (
132 Device {
133 context: Arc::clone(&context),
134 data: Box::new(device),
135 },
136 Queue {
137 context,
138 data: Box::new(queue),
139 },
140 )
141 })
142 }
143
144 /// Apply a callback to this `Adapter`'s underlying backend adapter.
145 ///
146 /// If this `Adapter` is implemented by the backend API given by `A` (Vulkan,
147 /// Dx12, etc.), then apply `hal_adapter_callback` to `Some(&adapter)`, where
148 /// `adapter` is the underlying backend adapter type, [`A::Adapter`].
149 ///
150 /// If this `Adapter` uses a different backend, apply `hal_adapter_callback`
151 /// to `None`.
152 ///
153 /// The adapter is locked for reading while `hal_adapter_callback` runs. If
154 /// the callback attempts to perform any `wgpu` operations that require
155 /// write access to the adapter, deadlock will occur. The locks are
156 /// automatically released when the callback returns.
157 ///
158 /// # Safety
159 ///
160 /// - The raw handle passed to the callback must not be manually destroyed.
161 ///
162 /// [`A::Adapter`]: hal::Api::Adapter
163 #[cfg(wgpu_core)]
164 pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
165 &self,
166 hal_adapter_callback: F,
167 ) -> R {
168 if let Some(ctx) = self
169 .context
170 .as_any()
171 .downcast_ref::<crate::backend::ContextWgpuCore>()
172 {
173 unsafe {
174 ctx.adapter_as_hal::<A, F, R>(
175 crate::context::downcast_ref(self.data.as_ref()),
176 hal_adapter_callback,
177 )
178 }
179 } else {
180 hal_adapter_callback(None)
181 }
182 }
183
184 /// Returns whether this adapter may present to the passed surface.
185 pub fn is_surface_supported(&self, surface: &Surface<'_>) -> bool {
186 DynContext::adapter_is_surface_supported(
187 &*self.context,
188 self.data.as_ref(),
189 surface.surface_data.as_ref(),
190 )
191 }
192
193 /// The features which can be used to create devices on this adapter.
194 pub fn features(&self) -> Features {
195 DynContext::adapter_features(&*self.context, self.data.as_ref())
196 }
197
198 /// The best limits which can be used to create devices on this adapter.
199 pub fn limits(&self) -> Limits {
200 DynContext::adapter_limits(&*self.context, self.data.as_ref())
201 }
202
203 /// Get info about the adapter itself.
204 pub fn get_info(&self) -> AdapterInfo {
205 DynContext::adapter_get_info(&*self.context, self.data.as_ref())
206 }
207
208 /// Get info about the adapter itself.
209 pub fn get_downlevel_capabilities(&self) -> DownlevelCapabilities {
210 DynContext::adapter_downlevel_capabilities(&*self.context, self.data.as_ref())
211 }
212
213 /// Returns the features supported for a given texture format by this adapter.
214 ///
215 /// Note that the WebGPU spec further restricts the available usages/features.
216 /// To disable these restrictions on a device, request the [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] feature.
217 pub fn get_texture_format_features(&self, format: TextureFormat) -> TextureFormatFeatures {
218 DynContext::adapter_get_texture_format_features(&*self.context, self.data.as_ref(), format)
219 }
220
221 /// Generates a timestamp using the clock used by the presentation engine.
222 ///
223 /// When comparing completely opaque timestamp systems, we need a way of generating timestamps that signal
224 /// the exact same time. You can do this by calling your own timestamp function immediately after a call to
225 /// this function. This should result in timestamps that are 0.5 to 5 microseconds apart. There are locks
226 /// that must be taken during the call, so don't call your function before.
227 ///
228 /// ```no_run
229 /// # let adapter: wgpu::Adapter = panic!();
230 /// # let some_code = || wgpu::PresentationTimestamp::INVALID_TIMESTAMP;
231 /// use std::time::{Duration, Instant};
232 /// let presentation = adapter.get_presentation_timestamp();
233 /// let instant = Instant::now();
234 ///
235 /// // We can now turn a new presentation timestamp into an Instant.
236 /// let some_pres_timestamp = some_code();
237 /// let duration = Duration::from_nanos((some_pres_timestamp.0 - presentation.0) as u64);
238 /// let new_instant: Instant = instant + duration;
239 /// ```
240 //
241 /// [Instant]: std::time::Instant
242 pub fn get_presentation_timestamp(&self) -> PresentationTimestamp {
243 DynContext::adapter_get_presentation_timestamp(&*self.context, self.data.as_ref())
244 }
245}