Skip to main content

wgpu/api/
adapter.rs

1use alloc::sync::Arc;
2use alloc::vec::Vec;
3use core::future::Future;
4#[cfg(wgpu_core)]
5use core::ops::Deref;
6use hashbrown::HashSet;
7use wgpu_sync::Mutex;
8
9use crate::*;
10
11/// Handle to a physical graphics and/or compute device.
12///
13/// Adapters can be created using [`Instance::request_adapter`]
14/// or other [`Instance`] methods.
15///
16/// Adapters can be used to open a connection to the corresponding [`Device`]
17/// on the host system by using [`Adapter::request_device`].
18///
19/// Does not have to be kept alive.
20///
21/// Corresponds to [WebGPU `GPUAdapter`](https://gpuweb.github.io/gpuweb/#gpu-adapter).
22#[derive(Debug, Clone)]
23pub struct Adapter {
24    pub(crate) inner: dispatch::DispatchAdapter,
25}
26#[cfg(send_sync)]
27static_assertions::assert_impl_all!(Adapter: Send, Sync);
28
29crate::cmp::impl_eq_ord_hash_proxy!(Adapter => .inner);
30
31pub use wgt::RequestAdapterOptions as RequestAdapterOptionsBase;
32/// Additional information required when requesting an adapter.
33///
34/// For use with [`Instance::request_adapter`].
35///
36/// Corresponds to [WebGPU `GPURequestAdapterOptions`](
37/// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions).
38pub type RequestAdapterOptions<'a, 'b> = RequestAdapterOptionsBase<&'a Surface<'b>>;
39#[cfg(send_sync)]
40static_assertions::assert_impl_all!(RequestAdapterOptions<'_, '_>: Send, Sync);
41
42impl Adapter {
43    /// Requests a connection to a physical device, creating a logical device.
44    ///
45    /// Returns the [`Device`] together with a [`Queue`] that executes command buffers.
46    ///
47    /// [Per the WebGPU specification], an [`Adapter`] may only be used once to create a device.
48    /// If another device is wanted, call [`Instance::request_adapter()`] again to get a fresh
49    /// [`Adapter`].
50    /// However, `wgpu` does not currently enforce this restriction.
51    ///
52    /// # Panics
53    ///
54    /// - `request_device()` was already called on this `Adapter`.
55    /// - Features specified by `desc` are not supported by this adapter.
56    /// - Unsafe features were requested but not enabled when requesting the adapter.
57    /// - Limits requested exceed the values provided by the adapter.
58    /// - Adapter does not support all features wgpu requires to safely operate.
59    ///
60    /// [Per the WebGPU specification]: https://www.w3.org/TR/webgpu/#dom-gpuadapter-requestdevice
61    pub fn request_device(
62        &self,
63        desc: &DeviceDescriptor<'_>,
64    ) -> impl Future<Output = Result<(Device, Queue), RequestDeviceError>> + WasmNotSend {
65        let device = self.inner.request_device(desc);
66        async move {
67            device.await.map(|(device, queue)| {
68                (
69                    Device {
70                        inner: device,
71                        buffers: Arc::new(Mutex::new(HashSet::new())),
72                    },
73                    Queue { inner: queue },
74                )
75            })
76        }
77    }
78
79    /// Create a wgpu [`Device`] and [`Queue`] from a wgpu-hal [`hal::OpenDevice`].
80    ///
81    /// # Safety
82    ///
83    /// - `hal_device` must be created from this adapter internal handle.
84    /// - `desc.features` must be a subset of `hal_device`'s supported features.
85    #[cfg(wgpu_core)]
86    pub unsafe fn create_device_from_hal<A: hal::Api>(
87        &self,
88        hal_device: hal::OpenDevice<A>,
89        desc: &DeviceDescriptor<'_>,
90    ) -> Result<(Device, Queue), RequestDeviceError> {
91        let core_adapter = self.inner.as_core();
92        let (device, queue) = unsafe { core_adapter.create_device_from_hal(hal_device, desc) }?;
93
94        Ok((
95            Device {
96                inner: device.into(),
97                buffers: Arc::new(Mutex::new(HashSet::new())),
98            },
99            Queue {
100                inner: queue.into(),
101            },
102        ))
103    }
104
105    /// Get the [`wgpu_hal`] adapter from this `Adapter`.
106    ///
107    /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
108    /// and pass that struct to the to the `A` type parameter.
109    ///
110    /// Returns a guard that dereferences to the type of the hal backend
111    /// which implements [`A::Adapter`].
112    ///
113    /// # Types
114    ///
115    /// The returned type depends on the backend:
116    ///
117    #[doc = crate::macros::hal_type_vulkan!("Adapter")]
118    #[doc = crate::macros::hal_type_metal!("Adapter")]
119    #[doc = crate::macros::hal_type_dx12!("Adapter")]
120    #[doc = crate::macros::hal_type_gles!("Adapter")]
121    ///
122    /// # Errors
123    ///
124    /// This method will return None if:
125    /// - The adapter is not from the backend specified by `A`.
126    /// - The adapter is from the `webgpu` or `custom` backend.
127    ///
128    /// # Safety
129    ///
130    /// - The returned resource must not be destroyed unless the guard
131    ///   is the last reference to it and it is not in use by the GPU.
132    ///   The guard and handle may be dropped at any time however.
133    /// - All the safety requirements of wgpu-hal must be upheld.
134    ///
135    /// [`A::Adapter`]: hal::Api::Adapter
136    #[cfg(wgpu_core)]
137    pub unsafe fn as_hal<A: hal::Api>(
138        &self,
139    ) -> Option<impl Deref<Target = A::Adapter> + WasmNotSendSync> {
140        let adapter = self.inner.as_core_opt()?;
141
142        unsafe { adapter.as_hal::<A>() }
143    }
144
145    #[cfg(custom)]
146    /// Returns custom implementation of adapter (if custom backend and is internally T)
147    pub fn as_custom<T: custom::AdapterInterface>(&self) -> Option<&T> {
148        self.inner.as_custom()
149    }
150
151    #[cfg(custom)]
152    /// Creates Adapter from custom implementation
153    pub fn from_custom<T: custom::AdapterInterface>(adapter: T) -> Self {
154        Self {
155            inner: dispatch::DispatchAdapter::custom(adapter),
156        }
157    }
158
159    /// Returns whether this adapter may present to the passed surface.
160    pub fn is_surface_supported(&self, surface: &Surface<'_>) -> bool {
161        self.inner.is_surface_supported(&surface.inner)
162    }
163
164    /// The features which can be used to create devices on this adapter.
165    pub fn features(&self) -> Features {
166        self.inner.features()
167    }
168
169    /// The best limits which can be used to create devices on this adapter.
170    pub fn limits(&self) -> Limits {
171        self.inner.limits()
172    }
173
174    /// Get info about the adapter itself.
175    pub fn get_info(&self) -> AdapterInfo {
176        self.inner.get_info()
177    }
178
179    /// Get info about the adapter itself.
180    pub fn get_downlevel_capabilities(&self) -> DownlevelCapabilities {
181        self.inner.downlevel_capabilities()
182    }
183
184    /// Returns the features supported for a given texture format by this adapter.
185    ///
186    /// Note that the WebGPU spec further restricts the available usages/features.
187    /// To disable these restrictions on a device, request the [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] feature.
188    pub fn get_texture_format_features(&self, format: TextureFormat) -> TextureFormatFeatures {
189        self.inner.get_texture_format_features(format)
190    }
191
192    /// Generates a timestamp using the clock used by the presentation engine.
193    ///
194    /// When comparing completely opaque timestamp systems, we need a way of generating timestamps that signal
195    /// the exact same time. You can do this by calling your own timestamp function immediately after a call to
196    /// this function. This should result in timestamps that are 0.5 to 5 microseconds apart. There are locks
197    /// that must be taken during the call, so don't call your function before.
198    ///
199    /// ```no_run
200    /// # let adapter: wgpu::Adapter = panic!();
201    /// # let some_code = || wgpu::PresentationTimestamp::INVALID_TIMESTAMP;
202    /// use std::time::{Duration, Instant};
203    /// let presentation = adapter.get_presentation_timestamp();
204    /// let instant = Instant::now();
205    ///
206    /// // We can now turn a new presentation timestamp into an Instant.
207    /// let some_pres_timestamp = some_code();
208    /// let duration = Duration::from_nanos((some_pres_timestamp.0 - presentation.0) as u64);
209    /// let new_instant: Instant = instant + duration;
210    /// ```
211    //
212    /// [Instant]: std::time::Instant
213    pub fn get_presentation_timestamp(&self) -> PresentationTimestamp {
214        self.inner.get_presentation_timestamp()
215    }
216
217    /// Returns the supported cooperative matrix configurations for this adapter.
218    ///
219    /// Cooperative matrices enable hardware-accelerated matrix multiply-accumulate
220    /// operations where threads in a subgroup collectively process matrix tiles.
221    ///
222    /// Returns an empty vector if cooperative matrices are not supported.
223    ///
224    /// Requires [`Features::EXPERIMENTAL_COOPERATIVE_MATRIX`] to be meaningful.
225    pub fn cooperative_matrix_properties(&self) -> Vec<CooperativeMatrixProperties> {
226        self.inner.cooperative_matrix_properties()
227    }
228}
229
230#[cfg(wgpu_core)]
231impl Adapter {
232    /// Create a new adapter of wgpu from a wgpu-core adapter.
233    ///
234    /// # Arguments
235    ///
236    /// - `core_adapter` - wgpu-core adapter.
237    pub fn from_core(core_adapter: alloc::sync::Arc<wgc::instance::Adapter>) -> Self {
238        Self {
239            inner: crate::backend::wgpu_core::CoreAdapter::from_core(core_adapter).into(),
240        }
241    }
242
243    /// Get the [`wgpu_core`] adapter from this `Adapter`.
244    ///
245    /// Returns `None` if the adapter is not from the `wgpu_core` backend
246    pub fn as_core(&self) -> Option<alloc::sync::Arc<wgc::instance::Adapter>> {
247        self.inner.as_core_opt().map(|adapter| adapter.as_core())
248    }
249}