Skip to content

Commit

Permalink
StagingBelt: check for free chunks in the receiver as well as `free…
Browse files Browse the repository at this point in the history
…_chunks`. (gfx-rs#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.
  • Loading branch information
kpreid authored Jul 26, 2022
1 parent 271bb86 commit a420e45
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ the same every time it is rendered, we now warn if it is missing.
#### General
- Added downlevel restriction error message for `InvalidFormatUsages` error by @Seamooo in [#2886](https://github.com/gfx-rs/wgpu/pull/2886)

### Performance

- Made `StagingBelt::write_buffer()` check more thoroughly for reusable memory; by @kpreid in [#2906](https://github.com/gfx-rs/wgpu/pull/2906)

### Documentation

- Expanded `StagingBelt` documentation by @kpreid in [#2905](https://github.com/gfx-rs/wgpu/pull/2905)
Expand Down
48 changes: 29 additions & 19 deletions wgpu/src/util/belt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,27 @@ impl StagingBelt {
.position(|chunk| chunk.offset + size.get() <= chunk.size)
{
self.active_chunks.swap_remove(index)
} else if let Some(index) = self
.free_chunks
.iter()
.position(|chunk| size.get() <= chunk.size)
{
self.free_chunks.swap_remove(index)
} else {
let size = self.chunk_size.max(size.get());
Chunk {
buffer: Arc::new(device.create_buffer(&BufferDescriptor {
label: Some("(wgpu internal) StagingBelt staging buffer"),
self.receive_chunks(); // ensure self.free_chunks is up to date

if let Some(index) = self
.free_chunks
.iter()
.position(|chunk| size.get() <= chunk.size)
{
self.free_chunks.swap_remove(index)
} else {
let size = self.chunk_size.max(size.get());
Chunk {
buffer: Arc::new(device.create_buffer(&BufferDescriptor {
label: Some("(wgpu internal) StagingBelt staging buffer"),
size,
usage: BufferUsages::MAP_WRITE | BufferUsages::COPY_SRC,
mapped_at_creation: true,
})),
size,
usage: BufferUsages::MAP_WRITE | BufferUsages::COPY_SRC,
mapped_at_creation: true,
})),
size,
offset: 0,
offset: 0,
}
}
};

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

let sender = &self.sender;
for chunk in self.closed_chunks.drain(..) {
Expand All @@ -159,6 +160,15 @@ impl StagingBelt {
});
}
}

/// Move all chunks that the GPU is done with (and are now mapped again)
/// from `self.receiver` to `self.free_chunks`.
fn receive_chunks(&mut self) {
while let Ok(mut chunk) = self.receiver.try_recv() {
chunk.offset = 0;
self.free_chunks.push(chunk);
}
}
}

impl fmt::Debug for StagingBelt {
Expand Down

0 comments on commit a420e45

Please sign in to comment.