mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
wgpu-core: Move identity code to new identity module.
This commit is contained in:
parent
13bd3eea55
commit
29914b308f
@ -95,7 +95,7 @@ fn check_unstable(state: &OpState, api_name: &str) {
|
||||
}
|
||||
|
||||
pub type Instance =
|
||||
std::sync::Arc<wgpu_core::global::Global<wgpu_core::hub::IdentityManagerFactory>>;
|
||||
std::sync::Arc<wgpu_core::global::Global<wgpu_core::identity::IdentityManagerFactory>>;
|
||||
|
||||
struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId);
|
||||
impl Resource for WebGpuAdapter {
|
||||
@ -324,7 +324,7 @@ pub async fn op_webgpu_request_adapter(
|
||||
} else {
|
||||
state.put(std::sync::Arc::new(wgpu_core::global::Global::new(
|
||||
"webgpu",
|
||||
wgpu_core::hub::IdentityManagerFactory,
|
||||
wgpu_core::identity::IdentityManagerFactory,
|
||||
wgpu_types::InstanceDescriptor {
|
||||
backends,
|
||||
dx12_shader_compiler: wgpu_types::Dx12Compiler::Fxc,
|
||||
|
||||
@ -48,7 +48,7 @@ fn main() {
|
||||
IdentityPassThroughFactory,
|
||||
wgt::InstanceDescriptor::default(),
|
||||
);
|
||||
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
|
||||
let mut command_buffer_id_manager = wgc::identity::IdentityManager::default();
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
let surface = global.instance_create_surface(
|
||||
|
||||
@ -15,7 +15,9 @@ use std::{borrow::Cow, fmt::Debug, fs, marker::PhantomData, path::Path};
|
||||
#[derive(Debug)]
|
||||
pub struct IdentityPassThrough<I>(PhantomData<I>);
|
||||
|
||||
impl<I: Clone + Debug + wgc::id::TypedId> wgc::hub::IdentityHandler<I> for IdentityPassThrough<I> {
|
||||
impl<I: Clone + Debug + wgc::id::TypedId> wgc::identity::IdentityHandler<I>
|
||||
for IdentityPassThrough<I>
|
||||
{
|
||||
type Input = I;
|
||||
fn process(&self, id: I, backend: wgt::Backend) -> I {
|
||||
let (index, epoch, _backend) = id.unzip();
|
||||
@ -26,7 +28,7 @@ impl<I: Clone + Debug + wgc::id::TypedId> wgc::hub::IdentityHandler<I> for Ident
|
||||
|
||||
pub struct IdentityPassThroughFactory;
|
||||
|
||||
impl<I: Clone + Debug + wgc::id::TypedId> wgc::hub::IdentityHandlerFactory<I>
|
||||
impl<I: Clone + Debug + wgc::id::TypedId> wgc::identity::IdentityHandlerFactory<I>
|
||||
for IdentityPassThroughFactory
|
||||
{
|
||||
type Filter = IdentityPassThrough<I>;
|
||||
@ -34,7 +36,7 @@ impl<I: Clone + Debug + wgc::id::TypedId> wgc::hub::IdentityHandlerFactory<I>
|
||||
IdentityPassThrough(PhantomData)
|
||||
}
|
||||
}
|
||||
impl wgc::hub::GlobalIdentityHandlerFactory for IdentityPassThroughFactory {}
|
||||
impl wgc::identity::GlobalIdentityHandlerFactory for IdentityPassThroughFactory {}
|
||||
|
||||
pub trait GlobalPlay {
|
||||
fn encode_commands<A: wgc::hal_api::HalApi>(
|
||||
@ -47,7 +49,7 @@ pub trait GlobalPlay {
|
||||
device: wgc::id::DeviceId,
|
||||
action: trace::Action,
|
||||
dir: &Path,
|
||||
comb_manager: &mut wgc::hub::IdentityManager,
|
||||
comb_manager: &mut wgc::identity::IdentityManager,
|
||||
);
|
||||
}
|
||||
|
||||
@ -151,7 +153,7 @@ impl GlobalPlay for wgc::global::Global<IdentityPassThroughFactory> {
|
||||
device: wgc::id::DeviceId,
|
||||
action: trace::Action,
|
||||
dir: &Path,
|
||||
comb_manager: &mut wgc::hub::IdentityManager,
|
||||
comb_manager: &mut wgc::identity::IdentityManager,
|
||||
) {
|
||||
use wgc::device::trace::Action;
|
||||
log::info!("action {:?}", action);
|
||||
|
||||
@ -98,7 +98,7 @@ impl Test<'_> {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
|
||||
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
|
||||
let mut command_buffer_id_manager = wgc::identity::IdentityManager::default();
|
||||
println!("\t\t\tRunning...");
|
||||
for action in self.actions {
|
||||
wgc::gfx_select!(device => global.process(device, action, dir, &mut command_buffer_id_manager));
|
||||
|
||||
@ -91,8 +91,9 @@ use crate::{
|
||||
},
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Hub, Resource, Storage, Token},
|
||||
hub::{Hub, Resource, Storage, Token},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction},
|
||||
pipeline::{self, PipelineFlags},
|
||||
resource,
|
||||
|
||||
@ -7,8 +7,9 @@ use crate::{
|
||||
get_lowest_common_denom,
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{self, GlobalIdentityHandlerFactory, Token},
|
||||
hub::{self, Token},
|
||||
id::{BufferId, CommandEncoderId, DeviceId, TextureId, Valid},
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{MemoryInitKind, TextureInitRange},
|
||||
resource::{Texture, TextureClearMode},
|
||||
track::{TextureSelector, TextureTracker},
|
||||
|
||||
@ -13,8 +13,9 @@ use crate::{
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Storage, Token},
|
||||
hub::{Storage, Token},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::MemoryInitKind,
|
||||
pipeline,
|
||||
resource::{self, Buffer, Texture},
|
||||
|
||||
@ -23,8 +23,9 @@ use crate::track::{Tracker, UsageScope};
|
||||
use crate::{
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Storage, Token},
|
||||
hub::{Storage, Token},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
resource::{Buffer, Texture},
|
||||
Label, Stored,
|
||||
};
|
||||
|
||||
@ -6,8 +6,9 @@ use crate::{
|
||||
command::{CommandBuffer, CommandEncoderError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Storage, Token},
|
||||
hub::{Storage, Token},
|
||||
id::{self, Id, TypedId},
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::MemoryInitKind,
|
||||
resource::QuerySet,
|
||||
Epoch, FastHashMap, Index,
|
||||
|
||||
@ -16,8 +16,9 @@ use crate::{
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Storage, Token},
|
||||
hub::{Storage, Token},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
|
||||
pipeline::{self, PipelineFlags},
|
||||
resource::{self, Buffer, Texture, TextureView, TextureViewNotRenderableReason},
|
||||
|
||||
@ -7,8 +7,9 @@ use crate::{
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Storage, Token},
|
||||
hub::{Storage, Token},
|
||||
id::{BufferId, CommandEncoderId, TextureId, Valid},
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{
|
||||
has_copy_partial_init_tracker_coverage, MemoryInitKind, TextureInitRange,
|
||||
TextureInitTrackerAction,
|
||||
|
||||
@ -6,8 +6,10 @@ use crate::{
|
||||
DeviceError,
|
||||
},
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Hub, Token},
|
||||
id, resource,
|
||||
hub::{Hub, Token},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
resource,
|
||||
track::{BindGroupStates, RenderBundleScope, Tracker},
|
||||
RefCount, Stored, SubmissionIndex,
|
||||
};
|
||||
|
||||
@ -3,8 +3,9 @@ use crate::{
|
||||
device::life::WaitIdleError,
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Hub, Input, InvalidId, Storage, Token},
|
||||
hub::{Hub, InvalidId, Storage, Token},
|
||||
id,
|
||||
identity::{GlobalIdentityHandlerFactory, Input},
|
||||
init_tracker::{
|
||||
BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange,
|
||||
TextureInitTracker, TextureInitTrackerAction,
|
||||
|
||||
@ -10,8 +10,9 @@ use crate::{
|
||||
get_lowest_common_denom,
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Input, Token},
|
||||
hub::Token,
|
||||
id,
|
||||
identity::{GlobalIdentityHandlerFactory, Input},
|
||||
init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
|
||||
resource::{BufferAccessError, BufferMapState, StagingBuffer, TextureInner},
|
||||
track, FastHashSet, SubmissionIndex,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use core::fmt;
|
||||
use std::error::Error;
|
||||
|
||||
use crate::{gfx_select, global::Global, hub::IdentityManagerFactory};
|
||||
use crate::{gfx_select, global::Global, identity::IdentityManagerFactory};
|
||||
|
||||
pub struct ErrorFormatter<'a> {
|
||||
writer: &'a mut dyn fmt::Write,
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use crate::{
|
||||
hal_api::HalApi,
|
||||
hub::GlobalIdentityHandlerFactory,
|
||||
hub::Registry,
|
||||
hub::{Element, StorageReport},
|
||||
hub::{HubReport, Hubs},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
instance::{Instance, Surface},
|
||||
};
|
||||
|
||||
@ -156,7 +156,7 @@ impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn _test_send_sync(global: &Global<crate::hub::IdentityManagerFactory>) {
|
||||
fn _test_send_sync(global: &Global<crate::identity::IdentityManagerFactory>) {
|
||||
fn test_internal<T: Send + Sync>(_: T) {}
|
||||
test_internal(global)
|
||||
}
|
||||
|
||||
@ -2,7 +2,8 @@ use wgt::Backend;
|
||||
|
||||
use crate::{
|
||||
global::Global,
|
||||
hub::{GlobalIdentityHandlerFactory, Hub},
|
||||
hub::Hub,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
instance::{HalSurface, Instance, Surface},
|
||||
};
|
||||
|
||||
|
||||
@ -148,6 +148,8 @@ flagged as errors as well.
|
||||
[`Id<R>`]: crate::id::Id
|
||||
[wrapped in a mutex]: trait.IdentityHandler.html#impl-IdentityHandler%3CI%3E-for-Mutex%3CIdentityManager%3E
|
||||
[WebGPU]: https://www.w3.org/TR/webgpu/
|
||||
[`IdentityManager`]: crate::identity::IdentityManager
|
||||
[`Input<G, I>`]: crate::identity::Input
|
||||
|
||||
*/
|
||||
|
||||
@ -157,93 +159,20 @@ use crate::{
|
||||
device::Device,
|
||||
hal_api::HalApi,
|
||||
id,
|
||||
identity::{GlobalIdentityHandlerFactory, IdentityHandler, IdentityHandlerFactory},
|
||||
instance::{Adapter, HalSurface, Instance, Surface},
|
||||
pipeline::{ComputePipeline, RenderPipeline, ShaderModule},
|
||||
resource::{Buffer, QuerySet, Sampler, StagingBuffer, Texture, TextureClearMode, TextureView},
|
||||
Epoch, Index,
|
||||
};
|
||||
|
||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use wgt::Backend;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use std::cell::Cell;
|
||||
use std::{fmt::Debug, marker::PhantomData, mem, ops};
|
||||
|
||||
/// A simple structure to allocate [`Id`] identifiers.
|
||||
///
|
||||
/// Calling [`alloc`] returns a fresh, never-before-seen id. Calling [`free`]
|
||||
/// marks an id as dead; it will never be returned again by `alloc`.
|
||||
///
|
||||
/// Use `IdentityManager::default` to construct new instances.
|
||||
///
|
||||
/// `IdentityManager` returns `Id`s whose index values are suitable for use as
|
||||
/// indices into a `Storage<T>` that holds those ids' referents:
|
||||
///
|
||||
/// - Every live id has a distinct index value. Each live id's index selects a
|
||||
/// distinct element in the vector.
|
||||
///
|
||||
/// - `IdentityManager` prefers low index numbers. If you size your vector to
|
||||
/// accommodate the indices produced here, the vector's length will reflect
|
||||
/// the highwater mark of actual occupancy.
|
||||
///
|
||||
/// - `IdentityManager` reuses the index values of freed ids before returning
|
||||
/// ids with new index values. Freed vector entries get reused.
|
||||
///
|
||||
/// See the module-level documentation for an overview of how this
|
||||
/// fits together.
|
||||
///
|
||||
/// [`Id`]: crate::id::Id
|
||||
/// [`Backend`]: wgt::Backend;
|
||||
/// [`alloc`]: IdentityManager::alloc
|
||||
/// [`free`]: IdentityManager::free
|
||||
#[derive(Debug, Default)]
|
||||
pub struct IdentityManager {
|
||||
/// Available index values. If empty, then `epochs.len()` is the next index
|
||||
/// to allocate.
|
||||
free: Vec<Index>,
|
||||
|
||||
/// The next or currently-live epoch value associated with each `Id` index.
|
||||
///
|
||||
/// If there is a live id with index `i`, then `epochs[i]` is its epoch; any
|
||||
/// id with the same index but an older epoch is dead.
|
||||
///
|
||||
/// If index `i` is currently unused, `epochs[i]` is the epoch to use in its
|
||||
/// next `Id`.
|
||||
epochs: Vec<Epoch>,
|
||||
}
|
||||
|
||||
impl IdentityManager {
|
||||
/// Allocate a fresh, never-before-seen id with the given `backend`.
|
||||
///
|
||||
/// The backend is incorporated into the id, so that ids allocated with
|
||||
/// different `backend` values are always distinct.
|
||||
pub fn alloc<I: id::TypedId>(&mut self, backend: Backend) -> I {
|
||||
match self.free.pop() {
|
||||
Some(index) => I::zip(index, self.epochs[index as usize], backend),
|
||||
None => {
|
||||
let epoch = 1;
|
||||
let id = I::zip(self.epochs.len() as Index, epoch, backend);
|
||||
self.epochs.push(epoch);
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Free `id`. It will never be returned from `alloc` again.
|
||||
pub fn free<I: id::TypedId + Debug>(&mut self, id: I) {
|
||||
let (index, epoch, _backend) = id.unzip();
|
||||
let pe = &mut self.epochs[index as usize];
|
||||
assert_eq!(*pe, epoch);
|
||||
// If the epoch reaches EOL, the index doesn't go
|
||||
// into the free list, will never be reused again.
|
||||
if epoch < id::EPOCH_MASK {
|
||||
*pe = epoch + 1;
|
||||
self.free.push(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry in a `Storage::map` table.
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Element<T> {
|
||||
@ -654,96 +583,6 @@ impl<'a, T> Drop for Token<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that can build true ids from proto-ids, and free true ids.
|
||||
///
|
||||
/// For some implementations, the true id is based on the proto-id.
|
||||
/// The caller is responsible for providing well-allocated proto-ids.
|
||||
///
|
||||
/// For other implementations, the proto-id carries no information
|
||||
/// (it's `()`, say), and this `IdentityHandler` type takes care of
|
||||
/// allocating a fresh true id.
|
||||
///
|
||||
/// See the module-level documentation for details.
|
||||
pub trait IdentityHandler<I>: Debug {
|
||||
/// The type of proto-id consumed by this filter, to produce a true id.
|
||||
type Input: Clone + Debug;
|
||||
|
||||
/// Given a proto-id value `id`, return a true id for `backend`.
|
||||
fn process(&self, id: Self::Input, backend: Backend) -> I;
|
||||
|
||||
/// Free the true id `id`.
|
||||
fn free(&self, id: I);
|
||||
}
|
||||
|
||||
impl<I: id::TypedId + Debug> IdentityHandler<I> for Mutex<IdentityManager> {
|
||||
type Input = ();
|
||||
fn process(&self, _id: Self::Input, backend: Backend) -> I {
|
||||
self.lock().alloc(backend)
|
||||
}
|
||||
fn free(&self, id: I) {
|
||||
self.lock().free(id)
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that can produce [`IdentityHandler`] filters for ids of type `I`.
|
||||
///
|
||||
/// See the module-level documentation for details.
|
||||
pub trait IdentityHandlerFactory<I> {
|
||||
/// The type of filter this factory constructs.
|
||||
///
|
||||
/// "Filter" and "handler" seem to both mean the same thing here:
|
||||
/// something that can produce true ids from proto-ids.
|
||||
type Filter: IdentityHandler<I>;
|
||||
|
||||
/// Create an [`IdentityHandler<I>`] implementation that can
|
||||
/// transform proto-ids into ids of type `I`.
|
||||
///
|
||||
/// [`IdentityHandler<I>`]: IdentityHandler
|
||||
fn spawn(&self) -> Self::Filter;
|
||||
}
|
||||
|
||||
/// A global identity handler factory based on [`IdentityManager`].
|
||||
///
|
||||
/// Each of this type's `IdentityHandlerFactory<I>::spawn` methods
|
||||
/// returns a `Mutex<IdentityManager<I>>`, which allocates fresh `I`
|
||||
/// ids itself, and takes `()` as its proto-id type.
|
||||
#[derive(Debug)]
|
||||
pub struct IdentityManagerFactory;
|
||||
|
||||
impl<I: id::TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
|
||||
type Filter = Mutex<IdentityManager>;
|
||||
fn spawn(&self) -> Self::Filter {
|
||||
Mutex::new(IdentityManager::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// A factory that can build [`IdentityHandler`]s for all resource
|
||||
/// types.
|
||||
pub trait GlobalIdentityHandlerFactory:
|
||||
IdentityHandlerFactory<id::AdapterId>
|
||||
+ IdentityHandlerFactory<id::DeviceId>
|
||||
+ IdentityHandlerFactory<id::PipelineLayoutId>
|
||||
+ IdentityHandlerFactory<id::ShaderModuleId>
|
||||
+ IdentityHandlerFactory<id::BindGroupLayoutId>
|
||||
+ IdentityHandlerFactory<id::BindGroupId>
|
||||
+ IdentityHandlerFactory<id::CommandBufferId>
|
||||
+ IdentityHandlerFactory<id::RenderBundleId>
|
||||
+ IdentityHandlerFactory<id::RenderPipelineId>
|
||||
+ IdentityHandlerFactory<id::ComputePipelineId>
|
||||
+ IdentityHandlerFactory<id::QuerySetId>
|
||||
+ IdentityHandlerFactory<id::BufferId>
|
||||
+ IdentityHandlerFactory<id::StagingBufferId>
|
||||
+ IdentityHandlerFactory<id::TextureId>
|
||||
+ IdentityHandlerFactory<id::TextureViewId>
|
||||
+ IdentityHandlerFactory<id::SamplerId>
|
||||
+ IdentityHandlerFactory<id::SurfaceId>
|
||||
{
|
||||
}
|
||||
|
||||
impl GlobalIdentityHandlerFactory for IdentityManagerFactory {}
|
||||
|
||||
pub type Input<G, I> = <<G as IdentityHandlerFactory<I>>::Filter as IdentityHandler<I>>::Input;
|
||||
|
||||
pub trait Resource {
|
||||
const TYPE: &'static str;
|
||||
fn life_guard(&self) -> &crate::LifeGuard;
|
||||
@ -1293,17 +1132,3 @@ impl<F: GlobalIdentityHandlerFactory> Hubs<F> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_epoch_end_of_life() {
|
||||
use id::TypedId as _;
|
||||
let mut man = IdentityManager::default();
|
||||
man.epochs.push(id::EPOCH_MASK);
|
||||
man.free.push(0);
|
||||
let id1 = man.alloc::<id::BufferId>(Backend::Empty);
|
||||
assert_eq!(id1.unzip().0, 0);
|
||||
man.free(id1);
|
||||
let id2 = man.alloc::<id::BufferId>(Backend::Empty);
|
||||
// confirm that the index 0 is no longer re-used
|
||||
assert_eq!(id2.unzip().0, 1);
|
||||
}
|
||||
|
||||
183
wgpu-core/src/identity.rs
Normal file
183
wgpu-core/src/identity.rs
Normal file
@ -0,0 +1,183 @@
|
||||
use parking_lot::Mutex;
|
||||
use wgt::Backend;
|
||||
|
||||
use crate::{id, Epoch, Index};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A simple structure to allocate [`Id`] identifiers.
|
||||
///
|
||||
/// Calling [`alloc`] returns a fresh, never-before-seen id. Calling [`free`]
|
||||
/// marks an id as dead; it will never be returned again by `alloc`.
|
||||
///
|
||||
/// Use `IdentityManager::default` to construct new instances.
|
||||
///
|
||||
/// `IdentityManager` returns `Id`s whose index values are suitable for use as
|
||||
/// indices into a `Storage<T>` that holds those ids' referents:
|
||||
///
|
||||
/// - Every live id has a distinct index value. Each live id's index selects a
|
||||
/// distinct element in the vector.
|
||||
///
|
||||
/// - `IdentityManager` prefers low index numbers. If you size your vector to
|
||||
/// accommodate the indices produced here, the vector's length will reflect
|
||||
/// the highwater mark of actual occupancy.
|
||||
///
|
||||
/// - `IdentityManager` reuses the index values of freed ids before returning
|
||||
/// ids with new index values. Freed vector entries get reused.
|
||||
///
|
||||
/// See the module-level documentation for an overview of how this
|
||||
/// fits together.
|
||||
///
|
||||
/// [`Id`]: crate::id::Id
|
||||
/// [`Backend`]: wgt::Backend;
|
||||
/// [`alloc`]: IdentityManager::alloc
|
||||
/// [`free`]: IdentityManager::free
|
||||
#[derive(Debug, Default)]
|
||||
pub struct IdentityManager {
|
||||
/// Available index values. If empty, then `epochs.len()` is the next index
|
||||
/// to allocate.
|
||||
free: Vec<Index>,
|
||||
|
||||
/// The next or currently-live epoch value associated with each `Id` index.
|
||||
///
|
||||
/// If there is a live id with index `i`, then `epochs[i]` is its epoch; any
|
||||
/// id with the same index but an older epoch is dead.
|
||||
///
|
||||
/// If index `i` is currently unused, `epochs[i]` is the epoch to use in its
|
||||
/// next `Id`.
|
||||
epochs: Vec<Epoch>,
|
||||
}
|
||||
|
||||
impl IdentityManager {
|
||||
/// Allocate a fresh, never-before-seen id with the given `backend`.
|
||||
///
|
||||
/// The backend is incorporated into the id, so that ids allocated with
|
||||
/// different `backend` values are always distinct.
|
||||
pub fn alloc<I: id::TypedId>(&mut self, backend: Backend) -> I {
|
||||
match self.free.pop() {
|
||||
Some(index) => I::zip(index, self.epochs[index as usize], backend),
|
||||
None => {
|
||||
let epoch = 1;
|
||||
let id = I::zip(self.epochs.len() as Index, epoch, backend);
|
||||
self.epochs.push(epoch);
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Free `id`. It will never be returned from `alloc` again.
|
||||
pub fn free<I: id::TypedId + Debug>(&mut self, id: I) {
|
||||
let (index, epoch, _backend) = id.unzip();
|
||||
let pe = &mut self.epochs[index as usize];
|
||||
assert_eq!(*pe, epoch);
|
||||
// If the epoch reaches EOL, the index doesn't go
|
||||
// into the free list, will never be reused again.
|
||||
if epoch < id::EPOCH_MASK {
|
||||
*pe = epoch + 1;
|
||||
self.free.push(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that can build true ids from proto-ids, and free true ids.
|
||||
///
|
||||
/// For some implementations, the true id is based on the proto-id.
|
||||
/// The caller is responsible for providing well-allocated proto-ids.
|
||||
///
|
||||
/// For other implementations, the proto-id carries no information
|
||||
/// (it's `()`, say), and this `IdentityHandler` type takes care of
|
||||
/// allocating a fresh true id.
|
||||
///
|
||||
/// See the module-level documentation for details.
|
||||
pub trait IdentityHandler<I>: Debug {
|
||||
/// The type of proto-id consumed by this filter, to produce a true id.
|
||||
type Input: Clone + Debug;
|
||||
|
||||
/// Given a proto-id value `id`, return a true id for `backend`.
|
||||
fn process(&self, id: Self::Input, backend: Backend) -> I;
|
||||
|
||||
/// Free the true id `id`.
|
||||
fn free(&self, id: I);
|
||||
}
|
||||
|
||||
impl<I: id::TypedId + Debug> IdentityHandler<I> for Mutex<IdentityManager> {
|
||||
type Input = ();
|
||||
fn process(&self, _id: Self::Input, backend: Backend) -> I {
|
||||
self.lock().alloc(backend)
|
||||
}
|
||||
fn free(&self, id: I) {
|
||||
self.lock().free(id)
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that can produce [`IdentityHandler`] filters for ids of type `I`.
|
||||
///
|
||||
/// See the module-level documentation for details.
|
||||
pub trait IdentityHandlerFactory<I> {
|
||||
/// The type of filter this factory constructs.
|
||||
///
|
||||
/// "Filter" and "handler" seem to both mean the same thing here:
|
||||
/// something that can produce true ids from proto-ids.
|
||||
type Filter: IdentityHandler<I>;
|
||||
|
||||
/// Create an [`IdentityHandler<I>`] implementation that can
|
||||
/// transform proto-ids into ids of type `I`.
|
||||
///
|
||||
/// [`IdentityHandler<I>`]: IdentityHandler
|
||||
fn spawn(&self) -> Self::Filter;
|
||||
}
|
||||
|
||||
/// A global identity handler factory based on [`IdentityManager`].
|
||||
///
|
||||
/// Each of this type's `IdentityHandlerFactory<I>::spawn` methods
|
||||
/// returns a `Mutex<IdentityManager<I>>`, which allocates fresh `I`
|
||||
/// ids itself, and takes `()` as its proto-id type.
|
||||
#[derive(Debug)]
|
||||
pub struct IdentityManagerFactory;
|
||||
|
||||
impl<I: id::TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
|
||||
type Filter = Mutex<IdentityManager>;
|
||||
fn spawn(&self) -> Self::Filter {
|
||||
Mutex::new(IdentityManager::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// A factory that can build [`IdentityHandler`]s for all resource
|
||||
/// types.
|
||||
pub trait GlobalIdentityHandlerFactory:
|
||||
IdentityHandlerFactory<id::AdapterId>
|
||||
+ IdentityHandlerFactory<id::DeviceId>
|
||||
+ IdentityHandlerFactory<id::PipelineLayoutId>
|
||||
+ IdentityHandlerFactory<id::ShaderModuleId>
|
||||
+ IdentityHandlerFactory<id::BindGroupLayoutId>
|
||||
+ IdentityHandlerFactory<id::BindGroupId>
|
||||
+ IdentityHandlerFactory<id::CommandBufferId>
|
||||
+ IdentityHandlerFactory<id::RenderBundleId>
|
||||
+ IdentityHandlerFactory<id::RenderPipelineId>
|
||||
+ IdentityHandlerFactory<id::ComputePipelineId>
|
||||
+ IdentityHandlerFactory<id::QuerySetId>
|
||||
+ IdentityHandlerFactory<id::BufferId>
|
||||
+ IdentityHandlerFactory<id::StagingBufferId>
|
||||
+ IdentityHandlerFactory<id::TextureId>
|
||||
+ IdentityHandlerFactory<id::TextureViewId>
|
||||
+ IdentityHandlerFactory<id::SamplerId>
|
||||
+ IdentityHandlerFactory<id::SurfaceId>
|
||||
{
|
||||
}
|
||||
|
||||
impl GlobalIdentityHandlerFactory for IdentityManagerFactory {}
|
||||
|
||||
pub type Input<G, I> = <<G as IdentityHandlerFactory<I>>::Filter as IdentityHandler<I>>::Input;
|
||||
|
||||
#[test]
|
||||
fn test_epoch_end_of_life() {
|
||||
use id::TypedId as _;
|
||||
let mut man = IdentityManager::default();
|
||||
man.epochs.push(id::EPOCH_MASK);
|
||||
man.free.push(0);
|
||||
let id1 = man.alloc::<id::BufferId>(Backend::Empty);
|
||||
assert_eq!(id1.unzip().0, 0);
|
||||
man.free(id1);
|
||||
let id2 = man.alloc::<id::BufferId>(Backend::Empty);
|
||||
// confirm that the index 0 is no longer re-used
|
||||
assert_eq!(id2.unzip().0, 1);
|
||||
}
|
||||
@ -2,8 +2,9 @@ use crate::{
|
||||
device::{Device, DeviceDescriptor},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Input, Token},
|
||||
hub::Token,
|
||||
id::{AdapterId, DeviceId, SurfaceId, Valid},
|
||||
identity::{GlobalIdentityHandlerFactory, Input},
|
||||
present::Presentation,
|
||||
LabelHelpers, LifeGuard, Stored, DOWNLEVEL_WARNING_MESSAGE,
|
||||
};
|
||||
|
||||
@ -46,6 +46,7 @@ pub mod global;
|
||||
pub mod hal_api;
|
||||
pub mod hub;
|
||||
pub mod id;
|
||||
pub mod identity;
|
||||
mod init_tracker;
|
||||
pub mod instance;
|
||||
pub mod pipeline;
|
||||
|
||||
@ -18,8 +18,9 @@ use crate::{
|
||||
device::{DeviceError, MissingDownlevelFlags},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Input, Token},
|
||||
hub::Token,
|
||||
id::{DeviceId, SurfaceId, TextureId, Valid},
|
||||
identity::{GlobalIdentityHandlerFactory, Input},
|
||||
init_tracker::TextureInitTracker,
|
||||
resource, track, LifeGuard, Stored,
|
||||
};
|
||||
|
||||
@ -2,8 +2,9 @@ use crate::{
|
||||
device::{DeviceError, HostMap, MissingDownlevelFlags, MissingFeatures},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{GlobalIdentityHandlerFactory, Resource, Token},
|
||||
hub::{Resource, Token},
|
||||
id::{AdapterId, DeviceId, SurfaceId, TextureId, Valid},
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{BufferInitTracker, TextureInitTracker},
|
||||
track::TextureSelector,
|
||||
validation::MissingBufferUsageError,
|
||||
|
||||
@ -26,7 +26,7 @@ use wgc::id::TypedId;
|
||||
|
||||
const LABEL: &str = "label";
|
||||
|
||||
pub struct Context(wgc::global::Global<wgc::hub::IdentityManagerFactory>);
|
||||
pub struct Context(wgc::global::Global<wgc::identity::IdentityManagerFactory>);
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
@ -45,7 +45,7 @@ impl Context {
|
||||
Self(unsafe {
|
||||
wgc::global::Global::from_hal_instance::<A>(
|
||||
"wgpu",
|
||||
wgc::hub::IdentityManagerFactory,
|
||||
wgc::identity::IdentityManagerFactory,
|
||||
hal_instance,
|
||||
)
|
||||
})
|
||||
@ -60,11 +60,11 @@ impl Context {
|
||||
|
||||
pub unsafe fn from_core_instance(core_instance: wgc::instance::Instance) -> Self {
|
||||
Self(unsafe {
|
||||
wgc::global::Global::from_instance(wgc::hub::IdentityManagerFactory, core_instance)
|
||||
wgc::global::Global::from_instance(wgc::identity::IdentityManagerFactory, core_instance)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn global(&self) -> &wgc::global::Global<wgc::hub::IdentityManagerFactory> {
|
||||
pub(crate) fn global(&self) -> &wgc::global::Global<wgc::identity::IdentityManagerFactory> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
@ -542,7 +542,7 @@ impl crate::Context for Context {
|
||||
fn init(instance_desc: wgt::InstanceDescriptor) -> Self {
|
||||
Self(wgc::global::Global::new(
|
||||
"wgpu",
|
||||
wgc::hub::IdentityManagerFactory,
|
||||
wgc::identity::IdentityManagerFactory,
|
||||
instance_desc,
|
||||
))
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user