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