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}