#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![allow(
// It is much clearer to assert negative conditions with eq! false
clippy::bool_assert_comparison,
// We use loops for getting early-out of scope without closures.
clippy::never_loop,
// We don't use syntax sugar where it's not necessary.
clippy::match_like_matches_macro,
// Redundant matching is more explicit.
clippy::redundant_pattern_matching,
// Explicit lifetimes are often easier to reason about.
clippy::needless_lifetimes,
// No need for defaults in the internal types.
clippy::new_without_default,
// Needless updates are more scaleable, easier to play with features.
clippy::needless_update,
// Need many arguments for some core functions to be able to re-use code in many situations.
clippy::too_many_arguments,
// For some reason `rustc` can warn about these in const generics even
// though they are required.
unused_braces,
)]
#![warn(
trivial_casts,
trivial_numeric_casts,
unsafe_op_in_unsafe_fn,
unused_extern_crates,
unused_qualifications,
// We don't match on a reference, unless required.
clippy::pattern_type_mismatch,
)]
pub mod binding_model;
pub mod command;
mod conv;
pub mod device;
pub mod error;
pub mod hub;
pub mod id;
mod init_tracker;
pub mod instance;
pub mod pipeline;
pub mod present;
pub mod resource;
mod track;
mod validation;
pub use hal::{api, MAX_BIND_GROUPS, MAX_COLOR_ATTACHMENTS, MAX_VERTEX_BUFFERS};
use atomic::{AtomicUsize, Ordering};
use std::{borrow::Cow, os::raw::c_char, ptr, sync::atomic};
type SubmissionIndex = hal::FenceValue;
type Index = u32;
type Epoch = u32;
pub type RawString = *const c_char;
pub type Label<'a> = Option<Cow<'a, str>>;
trait LabelHelpers<'a> {
fn borrow_option(&'a self) -> Option<&'a str>;
fn borrow_or_default(&'a self) -> &'a str;
}
impl<'a> LabelHelpers<'a> for Label<'a> {
fn borrow_option(&'a self) -> Option<&'a str> {
self.as_ref().map(|cow| cow.as_ref())
}
fn borrow_or_default(&'a self) -> &'a str {
self.borrow_option().unwrap_or_default()
}
}
#[derive(Debug)]
struct RefCount(ptr::NonNull<AtomicUsize>);
unsafe impl Send for RefCount {}
unsafe impl Sync for RefCount {}
impl RefCount {
const MAX: usize = 1 << 24;
fn new() -> RefCount {
let bx = Box::new(AtomicUsize::new(1));
Self(unsafe { ptr::NonNull::new_unchecked(Box::into_raw(bx)) })
}
fn load(&self) -> usize {
unsafe { self.0.as_ref() }.load(Ordering::Acquire)
}
}
impl Clone for RefCount {
fn clone(&self) -> Self {
let old_size = unsafe { self.0.as_ref() }.fetch_add(1, Ordering::AcqRel);
assert!(old_size < Self::MAX);
Self(self.0)
}
}
impl Drop for RefCount {
fn drop(&mut self) {
unsafe {
if self.0.as_ref().fetch_sub(1, Ordering::AcqRel) == 1 {
drop(Box::from_raw(self.0.as_ptr()));
}
}
}
}
#[derive(Debug)]
struct MultiRefCount(AtomicUsize);
impl MultiRefCount {
fn new() -> Self {
Self(AtomicUsize::new(1))
}
fn inc(&self) {
self.0.fetch_add(1, Ordering::AcqRel);
}
fn dec_and_check_empty(&self) -> bool {
self.0.fetch_sub(1, Ordering::AcqRel) == 1
}
}
#[derive(Debug)]
pub struct LifeGuard {
ref_count: Option<RefCount>,
submission_index: AtomicUsize,
#[cfg(debug_assertions)]
pub(crate) label: String,
}
impl LifeGuard {
#[allow(unused_variables)]
fn new(label: &str) -> Self {
Self {
ref_count: Some(RefCount::new()),
submission_index: AtomicUsize::new(0),
#[cfg(debug_assertions)]
label: label.to_string(),
}
}
fn add_ref(&self) -> RefCount {
self.ref_count.clone().unwrap()
}
fn use_at(&self, submit_index: SubmissionIndex) -> bool {
self.submission_index
.store(submit_index as _, Ordering::Release);
self.ref_count.is_some()
}
fn life_count(&self) -> SubmissionIndex {
self.submission_index.load(Ordering::Acquire) as _
}
}
#[derive(Clone, Debug)]
struct Stored<T> {
value: id::Valid<T>,
ref_count: RefCount,
}
const DOWNLEVEL_WARNING_MESSAGE: &str = "The underlying API or device in use does not \
support enough features to be a fully compliant implementation of WebGPU. A subset of the features can still be used. \
If you are running this program on native and not in a browser and wish to limit the features you use to the supported subset, \
call Adapter::downlevel_properties or Device::downlevel_properties to get a listing of the features the current \
platform supports.";
const DOWNLEVEL_ERROR_MESSAGE: &str = "This is not an invalid use of WebGPU: the underlying API or device does not \
support enough features to be a fully compliant implementation. A subset of the features can still be used. \
If you are running this program on native and not in a browser and wish to work around this issue, call \
Adapter::downlevel_properties or Device::downlevel_properties to get a listing of the features the current \
platform supports.";
macro_rules! define_backend_caller {
{ $public:ident, $private:ident if $feature:literal } => {
#[cfg(feature = $feature )]
#[macro_export]
macro_rules! $private {
( $call:expr ) => ( $call )
}
#[cfg(not(feature = $feature ))]
#[macro_export]
macro_rules! $private {
( $call:expr ) => (
panic!("Identifier refers to disabled backend feature {:?}", $feature)
)
}
#[doc(hidden)] pub use $private as $public;
}
}
define_backend_caller! { gfx_if_vulkan, gfx_if_vulkan_hidden if "vulkan" }
define_backend_caller! { gfx_if_metal, gfx_if_metal_hidden if "metal" }
define_backend_caller! { gfx_if_dx12, gfx_if_dx12_hidden if "dx12" }
define_backend_caller! { gfx_if_dx11, gfx_if_dx11_hidden if "dx11" }
define_backend_caller! { gfx_if_gles, gfx_if_gles_hidden if "gles" }
#[macro_export]
macro_rules! gfx_select {
($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {
match $id.backend() {
wgt::Backend::Vulkan => $crate::gfx_if_vulkan!($global.$method::<$crate::api::Vulkan>( $($param),* )),
wgt::Backend::Metal => $crate::gfx_if_metal!($global.$method::<$crate::api::Metal>( $($param),* )),
wgt::Backend::Dx12 => $crate::gfx_if_dx12!($global.$method::<$crate::api::Dx12>( $($param),* )),
wgt::Backend::Dx11 => $crate::gfx_if_dx11!($global.$method::<$crate::api::Dx11>( $($param),* )),
wgt::Backend::Gl => $crate::gfx_if_gles!($global.$method::<$crate::api::Gles>( $($param),+ )),
other => panic!("Unexpected backend {:?}", other),
}
};
}
type FastHashMap<K, V> =
std::collections::HashMap<K, V, std::hash::BuildHasherDefault<fxhash::FxHasher>>;
type FastHashSet<K> = std::collections::HashSet<K, std::hash::BuildHasherDefault<fxhash::FxHasher>>;
#[inline]
pub(crate) fn get_lowest_common_denom(a: u32, b: u32) -> u32 {
let gcd = if a >= b {
get_greatest_common_divisor(a, b)
} else {
get_greatest_common_divisor(b, a)
};
a * b / gcd
}
#[inline]
pub(crate) fn get_greatest_common_divisor(mut a: u32, mut b: u32) -> u32 {
assert!(a >= b);
loop {
let c = a % b;
if c == 0 {
return b;
} else {
a = b;
b = c;
}
}
}
#[test]
fn test_lcd() {
assert_eq!(get_lowest_common_denom(2, 2), 2);
assert_eq!(get_lowest_common_denom(2, 3), 6);
assert_eq!(get_lowest_common_denom(6, 4), 12);
}
#[test]
fn test_gcd() {
assert_eq!(get_greatest_common_divisor(5, 1), 1);
assert_eq!(get_greatest_common_divisor(4, 2), 2);
assert_eq!(get_greatest_common_divisor(6, 4), 2);
assert_eq!(get_greatest_common_divisor(7, 7), 7);
}