wgpu/api/
instance.rs

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