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}