wgpu_core/
lib.rs

1//! This library safely implements WebGPU on native platforms.
2//! It is designed for integration into browsers, as well as wrapping
3//! into other language-specific user-friendly libraries.
4//!
5//! ## Feature flags
6#![doc = document_features::document_features!()]
7//!
8
9#![no_std]
10// `-Znext-solver` requires deeper recursion limits (at least for now) to prove Send/Sync
11#![recursion_limit = "256"]
12// When we have no backends, we end up with a lot of dead or otherwise unreachable code.
13#![cfg_attr(
14    all(
15        not(all(feature = "vulkan", not(target_arch = "wasm32"))),
16        not(all(feature = "metal", any(target_vendor = "apple"))),
17        not(all(feature = "dx12", windows)),
18        not(feature = "gles"),
19    ),
20    allow(unused, clippy::let_and_return)
21)]
22#![cfg_attr(docsrs, feature(doc_cfg))]
23#![allow(
24    // It is much clearer to assert negative conditions with eq! false
25    clippy::bool_assert_comparison,
26    // We don't use syntax sugar where it's not necessary.
27    clippy::match_like_matches_macro,
28    // Redundant matching is more explicit.
29    clippy::redundant_pattern_matching,
30    // Explicit lifetimes are often easier to reason about.
31    clippy::needless_lifetimes,
32    // No need for defaults in the internal types.
33    clippy::new_without_default,
34    // Needless updates are more scalable, easier to play with features.
35    clippy::needless_update,
36    // Need many arguments for some core functions to be able to re-use code in many situations.
37    clippy::too_many_arguments,
38    // It gets in the way a lot and does not prevent bugs in practice.
39    clippy::pattern_type_mismatch,
40    // `wgpu-core` isn't entirely user-facing, so it's useful to document internal items.
41    rustdoc::private_intra_doc_links,
42)]
43#![expect(missing_debug_implementations, reason = "TODO")]
44#![warn(
45    clippy::alloc_instead_of_core,
46    clippy::ptr_as_ptr,
47    clippy::std_instead_of_alloc,
48    clippy::std_instead_of_core,
49    trivial_casts,
50    trivial_numeric_casts,
51    unsafe_op_in_unsafe_fn,
52    unused_extern_crates,
53    unused_qualifications
54)]
55// We use `Arc` in wgpu-core, but on wasm (unless opted out via `fragile-send-sync-non-atomic-wasm`)
56// wgpu-hal resources are not Send/Sync, causing a clippy warning for unnecessary `Arc`s.
57// We could use `Rc`s in this case as recommended, but unless atomics are enabled
58// this doesn't make a difference.
59// Therefore, this is only really a concern for users targeting WebGL
60// (the only reason to use wgpu-core on the web in the first place) that have atomics enabled.
61//
62// NOTE: Keep this in sync with `wgpu`.
63#![cfg_attr(not(send_sync), allow(clippy::arc_with_non_send_sync))]
64
65extern crate alloc;
66extern crate naga_types as nt;
67#[cfg(feature = "std")]
68extern crate std;
69extern crate wgpu_hal as hal;
70extern crate wgpu_types as wgt;
71
72mod as_hal;
73pub mod binding_model;
74pub mod command;
75mod conv;
76pub mod device;
77pub mod error;
78pub mod global;
79pub mod hub;
80pub mod id;
81pub mod identity;
82mod indirect_validation;
83mod init_tracker;
84pub mod instance;
85pub mod limits;
86mod lock;
87pub mod pipeline;
88mod pipeline_cache;
89mod pool;
90pub mod present;
91pub mod ray_tracing;
92pub mod registry;
93pub mod resource;
94mod snatch;
95pub mod storage;
96mod timestamp_normalization;
97mod track;
98mod weak_vec;
99// This is public for users who pre-compile shaders while still wanting to
100// preserve all run-time checks that `wgpu-core` does.
101// See <https://github.com/gfx-rs/wgpu/issues/3103>, after which this can be
102// made private again.
103mod scratch;
104pub mod validation;
105
106pub use validation::{map_storage_format_from_naga, map_storage_format_to_naga};
107
108pub use hal::{api, MAX_BIND_GROUPS, MAX_COLOR_ATTACHMENTS, MAX_VERTEX_BUFFERS};
109pub use naga;
110
111use alloc::{
112    borrow::{Cow, ToOwned as _},
113    string::String,
114};
115
116pub(crate) use nt::{FastHashMap, FastHashSet, FastIndexMap};
117
118/// The index of a queue submission.
119///
120/// These are the values stored in `Device::fence`.
121pub type SubmissionIndex = hal::FenceValue;
122
123type Index = u32;
124type Epoch = u32;
125
126pub type RawString = *const core::ffi::c_char;
127pub type Label<'a> = Option<Cow<'a, str>>;
128
129trait LabelHelpers<'a> {
130    fn to_hal(&'a self, flags: wgt::InstanceFlags) -> Option<&'a str>;
131    fn to_string(&self) -> String;
132}
133impl<'a> LabelHelpers<'a> for Label<'a> {
134    fn to_hal(&'a self, flags: wgt::InstanceFlags) -> Option<&'a str> {
135        if flags.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) {
136            return None;
137        }
138
139        self.as_deref()
140    }
141    fn to_string(&self) -> String {
142        self.as_deref().map(str::to_owned).unwrap_or_default()
143    }
144}
145
146pub fn hal_label<T: AsRef<str>>(opt: Option<T>, flags: wgt::InstanceFlags) -> Option<T> {
147    if flags.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) {
148        return None;
149    }
150
151    opt
152}
153
154const DOWNLEVEL_WARNING_MESSAGE: &str = concat!(
155    "The underlying API or device in use does not ",
156    "support enough features to be a fully compliant implementation of WebGPU. ",
157    "A subset of the features can still be used. ",
158    "If you are running this program on native and not in a browser and wish to limit ",
159    "the features you use to the supported subset, ",
160    "call Adapter::downlevel_properties or Device::downlevel_properties to get ",
161    "a listing of the features the current ",
162    "platform supports."
163);
164
165const DOWNLEVEL_ERROR_MESSAGE: &str = concat!(
166    "This is not an invalid use of WebGPU: the underlying API or device does not ",
167    "support enough features to be a fully compliant implementation. ",
168    "A subset of the features can still be used. ",
169    "If you are running this program on native and not in a browser ",
170    "and wish to work around this issue, call ",
171    "Adapter::downlevel_properties or Device::downlevel_properties ",
172    "to get a listing of the features the current platform supports."
173);
174
175#[cfg(feature = "api_log_info")]
176macro_rules! api_log {
177    ($($arg:tt)+) => (log::info!($($arg)+))
178}
179#[cfg(not(feature = "api_log_info"))]
180macro_rules! api_log {
181    ($($arg:tt)+) => (log::trace!($($arg)+))
182}
183
184#[cfg(feature = "api_log_info")]
185macro_rules! api_log_debug {
186    ($($arg:tt)+) => (log::info!($($arg)+))
187}
188#[cfg(not(feature = "api_log_info"))]
189macro_rules! api_log_debug {
190    ($($arg:tt)+) => (log::debug!($($arg)+))
191}
192
193pub(crate) use api_log;
194pub(crate) use api_log_debug;
195
196#[cfg(feature = "resource_log_info")]
197macro_rules! resource_log {
198    ($($arg:tt)+) => (log::info!($($arg)+))
199}
200#[cfg(not(feature = "resource_log_info"))]
201macro_rules! resource_log {
202    ($($arg:tt)+) => (log::trace!($($arg)+))
203}
204pub(crate) use resource_log;
205
206#[inline]
207pub(crate) fn get_lowest_common_denom(a: u32, b: u32) -> u32 {
208    let gcd = if a >= b {
209        get_greatest_common_divisor(a, b)
210    } else {
211        get_greatest_common_divisor(b, a)
212    };
213    a * b / gcd
214}
215
216#[inline]
217pub(crate) fn get_greatest_common_divisor(mut a: u32, mut b: u32) -> u32 {
218    assert!(a >= b);
219    loop {
220        let c = a % b;
221        if c == 0 {
222            return b;
223        } else {
224            a = b;
225            b = c;
226        }
227    }
228}
229
230#[cfg(not(feature = "std"))]
231use core::cell::OnceCell as OnceCellOrLock;
232#[cfg(feature = "std")]
233use std::sync::OnceLock as OnceCellOrLock;
234
235#[cfg(test)]
236mod tests {
237    use super::*;
238
239    #[test]
240    fn test_lcd() {
241        assert_eq!(get_lowest_common_denom(2, 2), 2);
242        assert_eq!(get_lowest_common_denom(2, 3), 6);
243        assert_eq!(get_lowest_common_denom(6, 4), 12);
244    }
245
246    #[test]
247    fn test_gcd() {
248        assert_eq!(get_greatest_common_divisor(5, 1), 1);
249        assert_eq!(get_greatest_common_divisor(4, 2), 2);
250        assert_eq!(get_greatest_common_divisor(6, 4), 2);
251        assert_eq!(get_greatest_common_divisor(7, 7), 7);
252    }
253}