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 /// Generates memory report.
309 ///
310 /// Returns `None` if the feature is not supported by the backend
311 /// which happens only when WebGPU is pre-selected by the instance creation.
312 #[cfg(wgpu_core)]
313 pub fn generate_report(&self) -> Option<wgc::global::GlobalReport> {
314 self.inner.as_core_opt().map(|ctx| ctx.generate_report())
315 }
316}
317
318/// Interop with wgpu-hal.
319#[cfg(wgpu_core)]
320impl Instance {
321 /// Create an new instance of wgpu from a wgpu-hal instance. This is often useful
322 /// when you need to do backend specific logic, or interop with an existing backend
323 /// instance.
324 ///
325 /// # Types
326 ///
327 /// The type of `A::Instance` depends on the backend:
328 ///
329 #[doc = crate::macros::hal_type_vulkan!("Instance")]
330 #[doc = crate::macros::hal_type_metal!("Instance")]
331 #[doc = crate::macros::hal_type_dx12!("Instance")]
332 #[doc = crate::macros::hal_type_gles!("Instance")]
333 ///
334 /// # Safety
335 ///
336 /// - The `hal_instance` must be a valid and usable instance of the backend specified by `A`.
337 /// - wgpu will act like it has complete ownership of this instance, and will destroy it
338 /// when the last reference to the instance, internal or external, is dropped.
339 pub unsafe fn from_hal<A: hal::Api>(hal_instance: A::Instance) -> Self {
340 Self {
341 inner: unsafe {
342 crate::backend::ContextWgpuCore::from_hal_instance::<A>(hal_instance).into()
343 },
344 }
345 }
346
347 /// Get the [`wgpu_hal`] instance from this `Instance`.
348 ///
349 /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
350 /// and pass that struct to the to the `A` type parameter.
351 ///
352 /// Returns a guard that dereferences to the type of the hal backend
353 /// which implements [`A::Instance`].
354 ///
355 /// # Types
356 ///
357 #[doc = crate::macros::hal_type_vulkan!("Instance")]
358 #[doc = crate::macros::hal_type_metal!("Instance")]
359 #[doc = crate::macros::hal_type_dx12!("Instance")]
360 #[doc = crate::macros::hal_type_gles!("Instance")]
361 ///
362 /// # Errors
363 ///
364 /// This method will return None if:
365 /// - The instance is not from the backend specified by `A`.
366 /// - The instance is from the `webgpu` or `custom` backend.
367 ///
368 /// # Safety
369 ///
370 /// - The returned resource must not be destroyed unless the guard
371 /// is the last reference to it and it is not in use by the GPU.
372 /// The guard and handle may be dropped at any time however.
373 /// - All the safety requirements of wgpu-hal must be upheld.
374 ///
375 /// [`A::Instance`]: hal::Api::Instance
376 pub unsafe fn as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
377 self.inner
378 .as_core_opt()
379 .and_then(|ctx| unsafe { ctx.instance_as_hal::<A>() })
380 }
381
382 /// Converts a wgpu-hal [`hal::ExposedAdapter`] to a wgpu [`Adapter`].
383 ///
384 /// # Types
385 ///
386 /// The type of `hal_adapter.adapter` depends on the backend:
387 ///
388 #[doc = crate::macros::hal_type_vulkan!("Adapter")]
389 #[doc = crate::macros::hal_type_metal!("Adapter")]
390 #[doc = crate::macros::hal_type_dx12!("Adapter")]
391 #[doc = crate::macros::hal_type_gles!("Adapter")]
392 ///
393 /// # Safety
394 ///
395 /// `hal_adapter` must be created from this instance internal handle.
396 pub unsafe fn create_adapter_from_hal<A: hal::Api>(
397 &self,
398 hal_adapter: hal::ExposedAdapter<A>,
399 ) -> Adapter {
400 let core_instance = self.inner.as_core();
401 let adapter = unsafe { core_instance.create_adapter_from_hal(hal_adapter) };
402 let core = backend::wgpu_core::CoreAdapter {
403 context: core_instance.clone(),
404 id: adapter,
405 };
406
407 Adapter { inner: core.into() }
408 }
409}
410
411/// Interop with wgpu-core.
412#[cfg(wgpu_core)]
413impl Instance {
414 /// Create an new instance of wgpu from a wgpu-core instance.
415 ///
416 /// # Arguments
417 ///
418 /// - `core_instance` - wgpu-core instance.
419 ///
420 /// # Safety
421 ///
422 /// Refer to the creation of wgpu-core Instance.
423 pub unsafe fn from_core(core_instance: Arc<wgc::instance::Instance>) -> Self {
424 Self {
425 inner: unsafe {
426 crate::backend::ContextWgpuCore::from_core_instance(core_instance).into()
427 },
428 }
429 }
430}
431
432/// Interop with custom backends.
433#[cfg(custom)]
434impl Instance {
435 /// Creates instance from custom context implementation
436 pub fn from_custom<T: InstanceInterface>(instance: T) -> Self {
437 Self {
438 inner: dispatch::DispatchInstance::Custom(backend::custom::DynContext::new(instance)),
439 }
440 }
441
442 #[cfg(custom)]
443 /// Returns custom implementation of Instance (if custom backend and is internally T)
444 pub fn as_custom<T: custom::InstanceInterface>(&self) -> Option<&T> {
445 self.inner.as_custom()
446 }
447}