wgpu/api/
instance.rs

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