1#![doc = document_features::document_features!()]
7#![cfg_attr(
11 all(
12 not(all(feature = "vulkan", not(target_arch = "wasm32"))),
13 not(all(feature = "metal", any(target_os = "macos", target_os = "ios"))),
14 not(all(feature = "dx12", windows)),
15 not(feature = "gles"),
16 ),
17 allow(unused, clippy::let_and_return)
18)]
19#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
20#![allow(
21 clippy::bool_assert_comparison,
23 clippy::never_loop,
25 clippy::match_like_matches_macro,
27 clippy::redundant_pattern_matching,
29 clippy::needless_lifetimes,
31 clippy::new_without_default,
33 clippy::needless_update,
35 clippy::too_many_arguments,
37 unused_braces,
40 clippy::pattern_type_mismatch,
42 rustdoc::private_intra_doc_links
44)]
45#![warn(
46 trivial_casts,
47 trivial_numeric_casts,
48 unsafe_op_in_unsafe_fn,
49 unused_extern_crates,
50 unused_qualifications
51)]
52
53pub mod binding_model;
54pub mod command;
55mod conv;
56pub mod device;
57pub mod error;
58pub mod global;
59pub mod hal_api;
60mod hash_utils;
61pub mod hub;
62pub mod id;
63pub mod identity;
64mod init_tracker;
65pub mod instance;
66mod lock;
67pub mod pipeline;
68mod pool;
69pub mod present;
70pub mod registry;
71pub mod resource;
72mod snatch;
73pub mod storage;
74mod track;
75pub mod validation;
80
81pub use hal::{api, MAX_BIND_GROUPS, MAX_COLOR_ATTACHMENTS, MAX_VERTEX_BUFFERS};
82pub use naga;
83
84use std::{borrow::Cow, os::raw::c_char};
85
86pub(crate) use hash_utils::*;
87
88type SubmissionIndex = hal::FenceValue;
92
93type Index = u32;
94type Epoch = u32;
95
96pub type RawString = *const c_char;
97pub type Label<'a> = Option<Cow<'a, str>>;
98
99trait LabelHelpers<'a> {
100 fn borrow_option(&'a self) -> Option<&'a str>;
101 fn to_hal(&'a self, flags: wgt::InstanceFlags) -> Option<&'a str>;
102 fn borrow_or_default(&'a self) -> &'a str;
103}
104impl<'a> LabelHelpers<'a> for Label<'a> {
105 fn borrow_option(&'a self) -> Option<&'a str> {
106 self.as_ref().map(|cow| cow.as_ref())
107 }
108 fn to_hal(&'a self, flags: wgt::InstanceFlags) -> Option<&'a str> {
109 if flags.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) {
110 return None;
111 }
112
113 self.as_ref().map(|cow| cow.as_ref())
114 }
115 fn borrow_or_default(&'a self) -> &'a str {
116 self.borrow_option().unwrap_or_default()
117 }
118}
119
120pub fn hal_label(opt: Option<&str>, flags: wgt::InstanceFlags) -> Option<&str> {
121 if flags.contains(wgt::InstanceFlags::DISCARD_HAL_LABELS) {
122 return None;
123 }
124
125 opt
126}
127
128const DOWNLEVEL_WARNING_MESSAGE: &str = "The underlying API or device in use does not \
129support enough features to be a fully compliant implementation of WebGPU. A subset of the features can still be used. \
130If you are running this program on native and not in a browser and wish to limit the features you use to the supported subset, \
131call Adapter::downlevel_properties or Device::downlevel_properties to get a listing of the features the current \
132platform supports.";
133const DOWNLEVEL_ERROR_MESSAGE: &str = "This is not an invalid use of WebGPU: the underlying API or device does not \
134support enough features to be a fully compliant implementation. A subset of the features can still be used. \
135If you are running this program on native and not in a browser and wish to work around this issue, call \
136Adapter::downlevel_properties or Device::downlevel_properties to get a listing of the features the current \
137platform supports.";
138
139macro_rules! define_backend_caller {
203 { $public:ident, $private:ident, $feature:literal if $cfg:meta } => {
204 #[cfg($cfg)]
205 #[macro_export]
206 macro_rules! $private {
207 ( $call:expr ) => ( $call )
208 }
209
210 #[cfg(not($cfg))]
211 #[macro_export]
212 macro_rules! $private {
213 ( $call:expr ) => (
214 panic!("Identifier refers to disabled backend feature {:?}", $feature)
215 )
216 }
217
218 #[doc(hidden)] pub use $private as $public;
220 }
221}
222
223define_backend_caller! { gfx_if_vulkan, gfx_if_vulkan_hidden, "vulkan" if all(feature = "vulkan", not(target_arch = "wasm32")) }
230define_backend_caller! { gfx_if_metal, gfx_if_metal_hidden, "metal" if all(feature = "metal", any(target_os = "macos", target_os = "ios")) }
231define_backend_caller! { gfx_if_dx12, gfx_if_dx12_hidden, "dx12" if all(feature = "dx12", windows) }
232define_backend_caller! { gfx_if_gles, gfx_if_gles_hidden, "gles" if feature = "gles" }
233define_backend_caller! { gfx_if_empty, gfx_if_empty_hidden, "empty" if all(
234 not(any(feature = "metal", feature = "vulkan", feature = "gles")),
235 any(target_os = "macos", target_os = "ios"),
236) }
237
238#[macro_export]
284macro_rules! gfx_select {
285 ($id:expr => $c0:ident.$c1:tt.$method:ident $params:tt) => {
287 $crate::gfx_select!($id => {$c0.$c1}, $method $params)
288 };
289
290 ($id:expr => $c0:ident.$method:ident $params:tt) => {
292 $crate::gfx_select!($id => {$c0}, $method $params)
293 };
294
295 ($id:expr => {$($c:tt)*}, $method:ident $params:tt) => {
296 match $id.backend() {
297 wgt::Backend::Vulkan => $crate::gfx_if_vulkan!($($c)*.$method::<$crate::api::Vulkan> $params),
298 wgt::Backend::Metal => $crate::gfx_if_metal!($($c)*.$method::<$crate::api::Metal> $params),
299 wgt::Backend::Dx12 => $crate::gfx_if_dx12!($($c)*.$method::<$crate::api::Dx12> $params),
300 wgt::Backend::Gl => $crate::gfx_if_gles!($($c)*.$method::<$crate::api::Gles> $params),
301 wgt::Backend::Empty => $crate::gfx_if_empty!($($c)*.$method::<$crate::api::Empty> $params),
302 other => panic!("Unexpected backend {:?}", other),
303 }
304 };
305}
306
307#[cfg(feature = "api_log_info")]
308macro_rules! api_log {
309 ($($arg:tt)+) => (log::info!($($arg)+))
310}
311#[cfg(not(feature = "api_log_info"))]
312macro_rules! api_log {
313 ($($arg:tt)+) => (log::trace!($($arg)+))
314}
315pub(crate) use api_log;
316
317#[cfg(feature = "resource_log_info")]
318macro_rules! resource_log {
319 ($($arg:tt)+) => (log::info!($($arg)+))
320}
321#[cfg(not(feature = "resource_log_info"))]
322macro_rules! resource_log {
323 ($($arg:tt)+) => (log::trace!($($arg)+))
324}
325pub(crate) use resource_log;
326
327#[inline]
328pub(crate) fn get_lowest_common_denom(a: u32, b: u32) -> u32 {
329 let gcd = if a >= b {
330 get_greatest_common_divisor(a, b)
331 } else {
332 get_greatest_common_divisor(b, a)
333 };
334 a * b / gcd
335}
336
337#[inline]
338pub(crate) fn get_greatest_common_divisor(mut a: u32, mut b: u32) -> u32 {
339 assert!(a >= b);
340 loop {
341 let c = a % b;
342 if c == 0 {
343 return b;
344 } else {
345 a = b;
346 b = c;
347 }
348 }
349}
350
351#[test]
352fn test_lcd() {
353 assert_eq!(get_lowest_common_denom(2, 2), 2);
354 assert_eq!(get_lowest_common_denom(2, 3), 6);
355 assert_eq!(get_lowest_common_denom(6, 4), 12);
356}
357
358#[test]
359fn test_gcd() {
360 assert_eq!(get_greatest_common_divisor(5, 1), 1);
361 assert_eq!(get_greatest_common_divisor(4, 2), 2);
362 assert_eq!(get_greatest_common_divisor(6, 4), 2);
363 assert_eq!(get_greatest_common_divisor(7, 7), 7);
364}