1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
//! Ranks for `wgpu-core` locks, restricting acquisition order.
//!
//! See [`LockRank`].
/// The rank of a lock.
///
/// Each [`Mutex`], [`RwLock`], and [`SnatchLock`] in `wgpu-core` has been
/// assigned a *rank*: a node in the DAG defined at the bottom of
/// `wgpu-core/src/lock/rank.rs`. The rank of the most recently
/// acquired lock you are still holding determines which locks you may
/// attempt to acquire next.
///
/// When you create a lock in `wgpu-core`, you must specify its rank
/// by passing in a [`LockRank`] value. This module declares a
/// pre-defined set of ranks to cover everything in `wgpu-core`, named
/// after the type in which they occur, and the name of the type's
/// field that is a lock. For example, [`CommandBuffer::data`] is a
/// `Mutex`, and its rank here is the constant
/// [`COMMAND_BUFFER_DATA`].
///
/// [`Mutex`]: parking_lot::Mutex
/// [`RwLock`]: parking_lot::RwLock
/// [`SnatchLock`]: crate::snatch::SnatchLock
/// [`CommandBuffer::data`]: crate::command::CommandBuffer::data
#[derive(Debug, Copy, Clone)]
pub struct LockRank {
/// The bit representing this lock.
///
/// There should only be a single bit set in this value.
pub(super) bit: LockRankSet,
/// A bitmask of permitted successor ranks.
///
/// If `rank` is the rank of the most recently acquired lock we
/// are still holding, then `rank.followers` is the mask of
/// locks we are allowed to acquire next.
///
/// The `define_lock_ranks!` macro ensures that there are no
/// cycles in the graph of lock ranks and their followers.
pub(super) followers: LockRankSet,
}
/// Define a set of lock ranks, and each rank's permitted successors.
macro_rules! define_lock_ranks {
{
$(
$( #[ $attr:meta ] )*
rank $name:ident $member:literal followed by { $( $follower:ident ),* $(,)? }
)*
} => {
// An enum that assigns a unique number to each rank.
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
enum LockRankNumber { $( $name, )* }
bitflags::bitflags! {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
/// A bitflags type representing a set of lock ranks.
pub struct LockRankSet: u64 {
$(
const $name = 1 << (LockRankNumber:: $name as u64);
)*
}
}
impl LockRankSet {
pub fn member_name(self) -> &'static str {
match self {
$(
LockRankSet:: $name => $member,
)*
_ => "<unrecognized LockRankSet bit>",
}
}
#[cfg_attr(not(feature = "observe_locks"), allow(dead_code))]
pub fn const_name(self) -> &'static str {
match self {
$(
LockRankSet:: $name => stringify!($name),
)*
_ => "<unrecognized LockRankSet bit>",
}
}
}
$(
// If there is any cycle in the ranking, the initializers
// for `followers` will be cyclic, and rustc will give us
// an error message explaining the cycle.
$( #[ $attr ] )*
pub const $name: LockRank = LockRank {
bit: LockRankSet:: $name,
followers: LockRankSet::empty() $( .union($follower.bit) )*,
};
)*
}
}
define_lock_ranks! {
rank COMMAND_BUFFER_DATA "CommandBuffer::data" followed by {
DEVICE_SNATCHABLE_LOCK,
DEVICE_USAGE_SCOPES,
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
BUFFER_MAP_STATE,
}
rank DEVICE_SNATCHABLE_LOCK "Device::snatchable_lock" followed by {
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
DEVICE_TRACE,
BUFFER_MAP_STATE,
// Uncomment this to see an interesting cycle.
// COMMAND_BUFFER_DATA,
}
rank BUFFER_MAP_STATE "Buffer::map_state" followed by {
DEVICE_PENDING_WRITES,
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
DEVICE_TRACE,
}
rank DEVICE_PENDING_WRITES "Device::pending_writes" followed by {
COMMAND_ALLOCATOR_FREE_ENCODERS,
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
DEVICE_LIFE_TRACKER,
}
rank DEVICE_LIFE_TRACKER "Device::life_tracker" followed by {
COMMAND_ALLOCATOR_FREE_ENCODERS,
DEVICE_TRACE,
}
rank COMMAND_ALLOCATOR_FREE_ENCODERS "CommandAllocator::free_encoders" followed by {
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
}
rank BUFFER_BIND_GROUPS "Buffer::bind_groups" followed by { }
rank BUFFER_INITIALIZATION_STATUS "Buffer::initialization_status" followed by { }
rank DEVICE_DEFERRED_DESTROY "Device::deferred_destroy" followed by { }
rank DEVICE_FENCE "Device::fence" followed by { }
#[allow(dead_code)]
rank DEVICE_TRACE "Device::trace" followed by { }
rank DEVICE_TRACKERS "Device::trackers" followed by { }
rank DEVICE_USAGE_SCOPES "Device::usage_scopes" followed by { }
rank IDENTITY_MANAGER_VALUES "IdentityManager::values" followed by { }
rank REGISTRY_STORAGE "Registry::storage" followed by { }
rank RESOURCE_POOL_INNER "ResourcePool::inner" followed by { }
rank SHARED_TRACKER_INDEX_ALLOCATOR_INNER "SharedTrackerIndexAllocator::inner" followed by { }
rank SURFACE_PRESENTATION "Surface::presentation" followed by { }
rank TEXTURE_BIND_GROUPS "Texture::bind_groups" followed by { }
rank TEXTURE_INITIALIZATION_STATUS "Texture::initialization_status" followed by { }
rank TEXTURE_VIEWS "Texture::views" followed by { }
#[cfg(test)]
rank PAWN "pawn" followed by { ROOK, BISHOP }
#[cfg(test)]
rank ROOK "rook" followed by { KNIGHT }
#[cfg(test)]
rank KNIGHT "knight" followed by { }
#[cfg(test)]
rank BISHOP "bishop" followed by { }
}