Skip to content

Commit a420e45

Browse files
authored
StagingBelt: check for free chunks in the receiver as well as free_chunks. (#2906)
* StagingBelt: check for free chunks in the `receiver` as well as `free_chunks`. Previously, chunks would only be taken from the GPU callback receiver and put on `free_chunks` during `finish()`. So, there might be chunks that are actually available for use but wouldn't be used. Now, we consult the receiver whenever we're about to consult the `free_chunks`, so the reuse of chunks will be as good as possible (given the application's uses of operations that trigger `map_async` callbacks). * Changelog entry.
1 parent 271bb86 commit a420e45

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ the same every time it is rendered, we now warn if it is missing.
7272
#### General
7373
- Added downlevel restriction error message for `InvalidFormatUsages` error by @Seamooo in [#2886](https://github.com/gfx-rs/wgpu/pull/2886)
7474

75+
### Performance
76+
77+
- Made `StagingBelt::write_buffer()` check more thoroughly for reusable memory; by @kpreid in [#2906](https://github.com/gfx-rs/wgpu/pull/2906)
78+
7579
### Documentation
7680

7781
- Expanded `StagingBelt` documentation by @kpreid in [#2905](https://github.com/gfx-rs/wgpu/pull/2905)

wgpu/src/util/belt.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -88,23 +88,27 @@ impl StagingBelt {
8888
.position(|chunk| chunk.offset + size.get() <= chunk.size)
8989
{
9090
self.active_chunks.swap_remove(index)
91-
} else if let Some(index) = self
92-
.free_chunks
93-
.iter()
94-
.position(|chunk| size.get() <= chunk.size)
95-
{
96-
self.free_chunks.swap_remove(index)
9791
} else {
98-
let size = self.chunk_size.max(size.get());
99-
Chunk {
100-
buffer: Arc::new(device.create_buffer(&BufferDescriptor {
101-
label: Some("(wgpu internal) StagingBelt staging buffer"),
92+
self.receive_chunks(); // ensure self.free_chunks is up to date
93+
94+
if let Some(index) = self
95+
.free_chunks
96+
.iter()
97+
.position(|chunk| size.get() <= chunk.size)
98+
{
99+
self.free_chunks.swap_remove(index)
100+
} else {
101+
let size = self.chunk_size.max(size.get());
102+
Chunk {
103+
buffer: Arc::new(device.create_buffer(&BufferDescriptor {
104+
label: Some("(wgpu internal) StagingBelt staging buffer"),
105+
size,
106+
usage: BufferUsages::MAP_WRITE | BufferUsages::COPY_SRC,
107+
mapped_at_creation: true,
108+
})),
102109
size,
103-
usage: BufferUsages::MAP_WRITE | BufferUsages::COPY_SRC,
104-
mapped_at_creation: true,
105-
})),
106-
size,
107-
offset: 0,
110+
offset: 0,
111+
}
108112
}
109113
};
110114

@@ -142,10 +146,7 @@ impl StagingBelt {
142146
/// [`StagingBelt::write_buffer()`] are submitted. Additional calls are harmless.
143147
/// Not calling this as soon as possible may result in increased buffer memory usage.
144148
pub fn recall(&mut self) {
145-
while let Ok(mut chunk) = self.receiver.try_recv() {
146-
chunk.offset = 0;
147-
self.free_chunks.push(chunk);
148-
}
149+
self.receive_chunks();
149150

150151
let sender = &self.sender;
151152
for chunk in self.closed_chunks.drain(..) {
@@ -159,6 +160,15 @@ impl StagingBelt {
159160
});
160161
}
161162
}
163+
164+
/// Move all chunks that the GPU is done with (and are now mapped again)
165+
/// from `self.receiver` to `self.free_chunks`.
166+
fn receive_chunks(&mut self) {
167+
while let Ok(mut chunk) = self.receiver.try_recv() {
168+
chunk.offset = 0;
169+
self.free_chunks.push(chunk);
170+
}
171+
}
162172
}
163173

164174
impl fmt::Debug for StagingBelt {

0 commit comments

Comments
 (0)