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