Skip to content

Commit 004e3ef

Browse files
nicalcwfitzgerald
andauthored
Simplify the ID allocation in IdentityValues (#5229)
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
1 parent 66ba64b commit 004e3ef

File tree

2 files changed

+41
-23
lines changed

2 files changed

+41
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ Bottom level categories:
113113
- Fix panic when creating a surface while no backend is available. By @wumpf [#5166](https://github.com/gfx-rs/wgpu/pull/5166)
114114
- Correctly compute minimum buffer size for array-typed `storage` and `uniform` vars. By @jimblandy [#5222](https://github.com/gfx-rs/wgpu/pull/5222)
115115
- Fix timeout when presenting a surface where no work has been done. By @waywardmonkeys in [#5200](https://github.com/gfx-rs/wgpu/pull/5200)
116+
- Simplify and speed up the allocation of internal IDs. By @nical in [#5229](https://github.com/gfx-rs/wgpu/pull/5229)
116117
- Fix an issue where command encoders weren't properly freed if an error occurred during command encoding. By @ErichDonGubler in [#5251](https://github.com/gfx-rs/wgpu/pull/5251).
117118

118119
#### WGL

wgpu-core/src/identity.rs

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ use wgt::Backend;
33

44
use crate::{
55
id::{Id, Marker},
6-
Epoch, FastHashMap, Index,
6+
Epoch, Index,
77
};
88
use std::{fmt::Debug, marker::PhantomData};
99

10+
#[derive(Copy, Clone, Debug, PartialEq)]
11+
enum IdSource {
12+
External,
13+
Allocated,
14+
None,
15+
}
16+
1017
/// A simple structure to allocate [`Id`] identifiers.
1118
///
1219
/// Calling [`alloc`] returns a fresh, never-before-seen id. Calling [`free`]
@@ -34,12 +41,15 @@ use std::{fmt::Debug, marker::PhantomData};
3441
/// [`Backend`]: wgt::Backend;
3542
/// [`alloc`]: IdentityManager::alloc
3643
/// [`free`]: IdentityManager::free
37-
#[derive(Debug, Default)]
44+
#[derive(Debug)]
3845
pub(super) struct IdentityValues {
3946
free: Vec<(Index, Epoch)>,
40-
//sorted by Index
41-
used: FastHashMap<Epoch, Vec<Index>>,
47+
next_index: Index,
4248
count: usize,
49+
// Sanity check: The allocation logic works under the assumption that we don't
50+
// do a mix of allocating ids from here and providing ids manually for the same
51+
// storage container.
52+
id_source: IdSource,
4353
}
4454

4555
impl IdentityValues {
@@ -48,35 +58,41 @@ impl IdentityValues {
4858
/// The backend is incorporated into the id, so that ids allocated with
4959
/// different `backend` values are always distinct.
5060
pub fn alloc<T: Marker>(&mut self, backend: Backend) -> Id<T> {
61+
assert!(
62+
self.id_source != IdSource::External,
63+
"Mix of internally allocated and externally provided IDs"
64+
);
65+
self.id_source = IdSource::Allocated;
66+
5167
self.count += 1;
5268
match self.free.pop() {
5369
Some((index, epoch)) => Id::zip(index, epoch + 1, backend),
5470
None => {
71+
let index = self.next_index;
72+
self.next_index += 1;
5573
let epoch = 1;
56-
let used = self.used.entry(epoch).or_insert_with(Default::default);
57-
let index = if let Some(i) = used.iter().max_by_key(|v| *v) {
58-
i + 1
59-
} else {
60-
0
61-
};
62-
used.push(index);
6374
Id::zip(index, epoch, backend)
6475
}
6576
}
6677
}
6778

6879
pub fn mark_as_used<T: Marker>(&mut self, id: Id<T>) -> Id<T> {
80+
assert!(
81+
self.id_source != IdSource::Allocated,
82+
"Mix of internally allocated and externally provided IDs"
83+
);
84+
self.id_source = IdSource::External;
85+
6986
self.count += 1;
70-
let (index, epoch, _backend) = id.unzip();
71-
let used = self.used.entry(epoch).or_insert_with(Default::default);
72-
used.push(index);
7387
id
7488
}
7589

7690
/// Free `id`. It will never be returned from `alloc` again.
7791
pub fn release<T: Marker>(&mut self, id: Id<T>) {
78-
let (index, epoch, _backend) = id.unzip();
79-
self.free.push((index, epoch));
92+
if let IdSource::Allocated = self.id_source {
93+
let (index, epoch, _backend) = id.unzip();
94+
self.free.push((index, epoch));
95+
}
8096
self.count -= 1;
8197
}
8298

@@ -106,7 +122,12 @@ impl<T: Marker> IdentityManager<T> {
106122
impl<T: Marker> IdentityManager<T> {
107123
pub fn new() -> Self {
108124
Self {
109-
values: Mutex::new(IdentityValues::default()),
125+
values: Mutex::new(IdentityValues {
126+
free: Vec::new(),
127+
next_index: 0,
128+
count: 0,
129+
id_source: IdSource::None,
130+
}),
110131
_phantom: PhantomData,
111132
}
112133
}
@@ -115,15 +136,11 @@ impl<T: Marker> IdentityManager<T> {
115136
#[test]
116137
fn test_epoch_end_of_life() {
117138
use crate::id;
118-
119139
let man = IdentityManager::<id::markers::Buffer>::new();
120-
let forced_id = man.mark_as_used(id::BufferId::zip(0, 1, Backend::Empty));
121-
assert_eq!(forced_id.unzip().0, 0);
122140
let id1 = man.process(Backend::Empty);
123-
assert_eq!(id1.unzip().0, 1);
141+
assert_eq!(id1.unzip(), (0, 1, Backend::Empty));
124142
man.free(id1);
125143
let id2 = man.process(Backend::Empty);
126144
// confirm that the epoch 1 is no longer re-used
127-
assert_eq!(id2.unzip().0, 1);
128-
assert_eq!(id2.unzip().1, 2);
145+
assert_eq!(id2.unzip(), (0, 2, Backend::Empty));
129146
}

0 commit comments

Comments
 (0)