wgpu/api/
instance.rs

1use alloc::vec::Vec;
2use core::future::Future;
3
4use crate::{dispatch::InstanceInterface, util::Mutex, *};
5
6bitflags::bitflags! {
7    /// WGSL language extensions.
8    ///
9    /// WGSL spec.: <https://www.w3.org/TR/WGSL/#language-extensions-sec>
10    #[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
11    pub struct WgslLanguageFeatures: u32 {
12        /// <https://www.w3.org/TR/WGSL/#language_extension-readonly_and_readwrite_storage_textures>
13        const ReadOnlyAndReadWriteStorageTextures = 1 << 0;
14        /// <https://www.w3.org/TR/WGSL/#language_extension-packed_4x8_integer_dot_product>
15        const Packed4x8IntegerDotProduct = 1 << 1;
16        /// <https://www.w3.org/TR/WGSL/#language_extension-unrestricted_pointer_parameters>
17        const UnrestrictedPointerParameters = 1 << 2;
18        /// <https://www.w3.org/TR/WGSL/#language_extension-pointer_composite_access>
19        const PointerCompositeAccess = 1 << 3;
20        /// <https://www.w3.org/TR/WGSL/#language_extension-immediate_address_space>
21        const ImmediateAddressSpace = 1 << 4;
22    }
23}
24
25/// Contains the various entry points to start interacting with the system's GPUs.
26///
27/// This is the first thing you create when using wgpu.
28/// Its primary use is to create [`Adapter`]s and [`Surface`]s.
29///
30/// Does not have to be kept alive.
31///
32/// Corresponds to [WebGPU `GPU`](https://gpuweb.github.io/gpuweb/#gpu-interface).
33#[derive(Debug, Clone)]
34pub struct Instance {
35    inner: dispatch::DispatchInstance,
36}
37#[cfg(send_sync)]
38static_assertions::assert_impl_all!(Instance: Send, Sync);
39
40crate::cmp::impl_eq_ord_hash_proxy!(Instance => .inner);
41
42impl Default for Instance {
43    /// Creates a new instance of wgpu with default options.
44    ///
45    /// Backends are set to `Backends::all()`, and FXC is chosen as the `dx12_shader_compiler`.
46    ///
47    /// # Panics
48    ///
49    /// If no backend feature for the active target platform is enabled,
50    /// this method will panic, see [`Instance::enabled_backend_features()`].
51    fn default() -> Self {
52        // TODO: Differentiate constructors here too?
53        Self::new(InstanceDescriptor::new_without_display_handle())
54    }
55}
56
57impl Instance {
58    /// Create an new instance of wgpu using the given options and enabled backends.
59    ///
60    /// # Panics
61    ///
62    /// - If no backend feature for the active target platform is enabled,
63    ///   this method will panic; see [`Instance::enabled_backend_features()`].
64    #[allow(clippy::allow_attributes, unreachable_code)]
65    pub fn new(desc: InstanceDescriptor) -> Self {
66        if Self::enabled_backend_features().is_empty() {
67            panic!(
68                "No wgpu backend feature that is implemented for the target platform was enabled. \
69                 See `wgpu::Instance::enabled_backend_features()` for more information."
70            );
71        }
72
73        #[cfg(webgpu)]
74        {
75            let is_only_available_backend = !cfg!(wgpu_core);
76            let requested_webgpu = desc.backends.contains(Backends::BROWSER_WEBGPU);
77            let support_webgpu = crate::backend::get_browser_gpu_property()
78                .map(|maybe_gpu| maybe_gpu.is_some())
79                .unwrap_or(false);
80
81            if is_only_available_backend || (requested_webgpu && support_webgpu) {
82                return Self {
83                    inner: crate::backend::ContextWebGpu::new(desc).into(),
84                };
85            }
86        }
87
88        #[cfg(wgpu_core)]
89        {
90            return Self {
91                inner: crate::backend::ContextWgpuCore::new(desc).into(),
92            };
93        }
94
95        // Silence unused variable warnings without adding _ to the parameter name (which shows up in docs).
96        let _ = desc;
97
98        unreachable!(
99            "Earlier check of `enabled_backend_features` should have prevented getting here!"
100        );
101    }
102
103    /// Returns which backends can be picked for the current build configuration.
104    ///
105    /// The returned set depends on a combination of target platform and enabled features.
106    /// This does *not* do any runtime checks and is exclusively based on compile time information.
107    ///
108    /// `InstanceDescriptor::backends` does not need to be a subset of this,
109    /// but any backend that is not in this set, will not be picked.
110    pub const fn enabled_backend_features() -> Backends {
111        let mut backends = Backends::empty();
112        // `.set` and `|=` don't work in a `const` context.
113        if cfg!(noop) {
114            backends = backends.union(Backends::NOOP);
115        }
116        if cfg!(vulkan) {
117            backends = backends.union(Backends::VULKAN);
118        }
119        if cfg!(any(gles, webgl)) {
120            backends = backends.union(Backends::GL);
121        }
122        if cfg!(metal) {
123            backends = backends.union(Backends::METAL);
124        }
125        if cfg!(dx12) {
126            backends = backends.union(Backends::DX12);
127        }
128        if cfg!(webgpu) {
129            backends = backends.union(Backends::BROWSER_WEBGPU);
130        }
131        backends
132    }
133
134    /// Returns the set of [WGSL language extensions] supported by this instance.
135    ///
136    /// [WGSL language extensions]: https://www.w3.org/TR/webgpu/#gpuwgsllanguagefeatures
137    #[cfg(feature = "wgsl")]
138    pub fn wgsl_language_features(&self) -> WgslLanguageFeatures {
139        self.inner.wgsl_language_features()
140    }
141
142    /// Retrieves all available [`Adapter`]s that match the given [`Backends`].
143    ///
144    /// # Arguments
145    ///
146    /// - `backends` - Backends from which to enumerate adapters.
147    pub fn enumerate_adapters(&self, backends: Backends) -> impl Future<Output = Vec<Adapter>> {
148        let future = self.inner.enumerate_adapters(backends);
149
150        async move {
151            future
152                .await
153                .iter()
154                .map(|adapter| Adapter {
155                    inner: adapter.clone(),
156                })
157                .collect()
158        }
159    }
160
161    /// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`].
162    ///
163    /// Some options are "soft", so treated as non-mandatory. Others are "hard".
164    ///
165    /// If no adapters are found that satisfy all the "hard" options, an error is returned.
166    ///
167    /// When targeting WebGL2, a [`compatible_surface`](RequestAdapterOptions::compatible_surface)
168    /// must be specified; using `RequestAdapterOptions::default()` will not succeed.
169    pub fn request_adapter(
170        &self,
171        options: &RequestAdapterOptions<'_, '_>,
172    ) -> impl Future<Output = Result<Adapter, RequestAdapterError>> + WasmNotSend {
173        let future = self.inner.request_adapter(options);
174        async move { future.await.map(|adapter| Adapter { inner: adapter }) }
175    }
176
177    /// Creates a new surface targeting a given window/canvas/surface/etc..
178    ///
179    /// Internally, this creates surfaces for all backends that are enabled for this instance.
180    ///
181    /// See [`SurfaceTarget`] for what targets are supported.
182    /// See [`Instance::create_surface_unsafe()`] for surface creation with unsafe target variants.
183    ///
184    /// Most commonly used are window handles (or provider of windows handles)
185    /// which can be passed directly as they're automatically converted to [`SurfaceTarget`].
186    pub fn create_surface<'window>(
187        &self,
188        target: impl Into<SurfaceTarget<'window>>,
189    ) -> Result<Surface<'window>, CreateSurfaceError> {
190        // Handle origin (i.e. window) to optionally take ownership of to make the surface outlast the window.
191        let handle_source;
192
193        let target = target.into();
194        let mut surface = match target {
195            SurfaceTarget::Window(window) => unsafe {
196                let surface = self.create_surface_unsafe(
197                    SurfaceTargetUnsafe::from_window(&window).map_err(|e| CreateSurfaceError {
198                        inner: CreateSurfaceErrorKind::RawHandle(e),
199                    })?,
200                );
201                handle_source = Some(window);
202
203                surface
204            }?,
205            SurfaceTarget::DisplayAndWindow(display_and_window_handle) => unsafe {
206                let surface = self.create_surface_unsafe(
207                    SurfaceTargetUnsafe::from_display_and_window(
208                        &display_and_window_handle,
209                        &display_and_window_handle,
210                    )
211                    .map_err(|e| CreateSurfaceError {
212                        inner: CreateSurfaceErrorKind::RawHandle(e),
213                    })?,
214                );
215                handle_source = Some(display_and_window_handle);
216
217                surface
218            }?,
219            #[cfg(web)]
220            SurfaceTarget::Canvas(canvas) => {
221                handle_source = None;
222
223                let value: &wasm_bindgen::JsValue = &canvas;
224                let obj = core::ptr::NonNull::from(value).cast();
225                let raw_window_handle = raw_window_handle::WebCanvasWindowHandle::new(obj).into();
226                let raw_display_handle = raw_window_handle::WebDisplayHandle::new().into();
227
228                // Note that we need to call this while we still have `value` around.
229                // This is safe without storing canvas to `handle_origin` since the surface will create a copy internally.
230                unsafe {
231                    self.create_surface_unsafe(SurfaceTargetUnsafe::RawHandle {
232                        raw_display_handle: Some(raw_display_handle),
233                        raw_window_handle,
234                    })
235                }?
236            }
237            #[cfg(web)]
238            SurfaceTarget::OffscreenCanvas(canvas) => {
239                handle_source = None;
240
241                let value: &wasm_bindgen::JsValue = &canvas;
242                let obj = core::ptr::NonNull::from(value).cast();
243                let raw_window_handle =
244                    raw_window_handle::WebOffscreenCanvasWindowHandle::new(obj).into();
245                let raw_display_handle = raw_window_handle::WebDisplayHandle::new().into();
246
247                // Note that we need to call this while we still have `value` around.
248                // This is safe without storing canvas to `handle_origin` since the surface will create a copy internally.
249                unsafe {
250                    self.create_surface_unsafe(SurfaceTargetUnsafe::RawHandle {
251                        raw_display_handle: Some(raw_display_handle),
252                        raw_window_handle,
253                    })
254                }?
255            }
256        };
257
258        surface._handle_source = handle_source;
259
260        Ok(surface)
261    }
262
263    /// Creates a new surface targeting a given window/canvas/surface/etc. using an unsafe target.
264    ///
265    /// Internally, this creates surfaces for all backends that are enabled for this instance.
266    ///
267    /// See [`SurfaceTargetUnsafe`] for what targets are supported.
268    /// See [`Instance::create_surface`] for surface creation with safe target variants.
269    ///
270    /// # Safety
271    ///
272    /// - See respective [`SurfaceTargetUnsafe`] variants for safety requirements.
273    pub unsafe fn create_surface_unsafe<'window>(
274        &self,
275        target: SurfaceTargetUnsafe,
276    ) -> Result<Surface<'window>, CreateSurfaceError> {
277        let surface = unsafe { self.inner.create_surface(target)? };
278
279        Ok(Surface {
280            _handle_source: None,
281            inner: surface,
282            config: Mutex::new(None),
283        })
284    }
285
286    /// Polls all devices.
287    ///
288    /// If `force_wait` is true and this is not running on the web, then this
289    /// function will block until all in-flight buffers have been mapped and
290    /// all submitted commands have finished execution.
291    ///
292    /// Return `true` if all devices' queues are empty, or `false` if there are
293    /// queue submissions still in flight. (Note that, unless access to all
294    /// [`Queue`s] associated with this [`Instance`] is coordinated somehow,
295    /// this information could be out of date by the time the caller receives
296    /// it. `Queue`s can be shared between threads, and other threads could
297    /// submit new work at any time.)
298    ///
299    /// On the web, this is a no-op. `Device`s are automatically polled.
300    ///
301    /// [`Queue`s]: Queue
302    pub fn poll_all(&self, force_wait: bool) -> bool {
303        self.inner.poll_all_devices(force_wait)
304    }
305
306    /// Generates memory report.
307    ///
308    /// Returns `None` if the feature is not supported by the backend
309    /// which happens only when WebGPU is pre-selected by the instance creation.
310    #[cfg(wgpu_core)]
311    pub fn generate_report(&self) -> Option<wgc::global::GlobalReport> {
312        self.inner.as_core_opt().map(|ctx| ctx.generate_report())
313    }
314}
315
316/// Interop with wgpu-hal.
317#[cfg(wgpu_core)]
318impl Instance {
319    /// Create an new instance of wgpu from a wgpu-hal instance. This is often useful
320    /// when you need to do backend specific logic, or interop with an existing backend
321    /// instance.
322    ///
323    /// # Types
324    ///
325    /// The type of `A::Instance` depends on the backend:
326    ///
327    #[doc = crate::macros::hal_type_vulkan!("Instance")]
328    #[doc = crate::macros::hal_type_metal!("Instance")]
329    #[doc = crate::macros::hal_type_dx12!("Instance")]
330    #[doc = crate::macros::hal_type_gles!("Instance")]
331    ///
332    /// # Safety
333    ///
334    /// - The `hal_instance` must be a valid and usable instance of the backend specified by `A`.
335    /// - wgpu will act like it has complete ownership of this instance, and will destroy it
336    ///   when the last reference to the instance, internal or external, is dropped.
337    pub unsafe fn from_hal<A: hal::Api>(hal_instance: A::Instance) -> Self {
338        Self {
339            inner: unsafe {
340                crate::backend::ContextWgpuCore::from_hal_instance::<A>(hal_instance).into()
341            },
342        }
343    }
344
345    /// Get the [`wgpu_hal`] instance from this `Instance`.
346    ///
347    /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
348    /// and pass that struct to the to the `A` type parameter.
349    ///
350    /// Returns a guard that dereferences to the type of the hal backend
351    /// which implements [`A::Instance`].
352    ///
353    /// # Types
354    ///
355    #[doc = crate::macros::hal_type_vulkan!("Instance")]
356    #[doc = crate::macros::hal_type_metal!("Instance")]
357    #[doc = crate::macros::hal_type_dx12!("Instance")]
358    #[doc = crate::macros::hal_type_gles!("Instance")]
359    ///
360    /// # Errors
361    ///
362    /// This method will return None if:
363    /// - The instance is not from the backend specified by `A`.
364    /// - The instance is from the `webgpu` or `custom` backend.
365    ///
366    /// # Safety
367    ///
368    /// - The returned resource must not be destroyed unless the guard
369    ///   is the last reference to it and it is not in use by the GPU.
370    ///   The guard and handle may be dropped at any time however.
371    /// - All the safety requirements of wgpu-hal must be upheld.
372    ///
373    /// [`A::Instance`]: hal::Api::Instance
374    pub unsafe fn as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
375        self.inner
376            .as_core_opt()
377            .and_then(|ctx| unsafe { ctx.instance_as_hal::<A>() })
378    }
379
380    /// Converts a wgpu-hal [`hal::ExposedAdapter`] to a wgpu [`Adapter`].
381    ///
382    /// # Types
383    ///
384    /// The type of `hal_adapter.adapter` depends on the backend:
385    ///
386    #[doc = crate::macros::hal_type_vulkan!("Adapter")]
387    #[doc = crate::macros::hal_type_metal!("Adapter")]
388    #[doc = crate::macros::hal_type_dx12!("Adapter")]
389    #[doc = crate::macros::hal_type_gles!("Adapter")]
390    ///
391    /// # Safety
392    ///
393    /// `hal_adapter` must be created from this instance internal handle.
394    pub unsafe fn create_adapter_from_hal<A: hal::Api>(
395        &self,
396        hal_adapter: hal::ExposedAdapter<A>,
397    ) -> Adapter {
398        let core_instance = self.inner.as_core();
399        let adapter = unsafe { core_instance.create_adapter_from_hal(hal_adapter) };
400        let core = backend::wgpu_core::CoreAdapter {
401            context: core_instance.clone(),
402            id: adapter,
403        };
404
405        Adapter { inner: core.into() }
406    }
407}
408
409/// Interop with wgpu-core.
410#[cfg(wgpu_core)]
411impl Instance {
412    /// Create an new instance of wgpu from a wgpu-core instance.
413    ///
414    /// # Arguments
415    ///
416    /// - `core_instance` - wgpu-core instance.
417    ///
418    /// # Safety
419    ///
420    /// Refer to the creation of wgpu-core Instance.
421    pub unsafe fn from_core(core_instance: wgc::instance::Instance) -> Self {
422        Self {
423            inner: unsafe {
424                crate::backend::ContextWgpuCore::from_core_instance(core_instance).into()
425            },
426        }
427    }
428}
429
430/// Interop with custom backends.
431#[cfg(custom)]
432impl Instance {
433    /// Creates instance from custom context implementation
434    pub fn from_custom<T: InstanceInterface>(instance: T) -> Self {
435        Self {
436            inner: dispatch::DispatchInstance::Custom(backend::custom::DynContext::new(instance)),
437        }
438    }
439
440    #[cfg(custom)]
441    /// Returns custom implementation of Instance (if custom backend and is internally T)
442    pub fn as_custom<T: custom::InstanceInterface>(&self) -> Option<&T> {
443        self.inner.as_custom()
444    }
445}