Skip to content

Add StagingBelt::finish_and_recall_on_submit#9506

Open
ruihe774 wants to merge 1 commit intogfx-rs:trunkfrom
ruihe774:belt_auto_map
Open

Add StagingBelt::finish_and_recall_on_submit#9506
ruihe774 wants to merge 1 commit intogfx-rs:trunkfrom
ruihe774:belt_auto_map

Conversation

@ruihe774
Copy link
Copy Markdown

@ruihe774 ruihe774 commented May 5, 2026

Connections

Builds on the original StagingBelt introduction in gfx-rs/wgpu-rs#408.

Description

Adds StagingBelt::finish_and_recall_on_submit, a convenience method that combines finish() and recall() into a single call. It defers the closed-chunk re-map via CommandEncoder::map_buffer_on_submit, so the chunks are returned automatically once the encoder is submitted — no explicit recall() is needed afterward.

This shortens the typical staging-belt usage from four steps to three:

  1. write_buffer / allocate and write data.
  2. finish_and_recall_on_submit(&encoder).
  3. Submit the encoder's command buffer.

The semantics match finish() followed by recall(), the only difference being that the re-map is scheduled to run when the submission completes rather than triggered eagerly by the user.

Testing

Added staging_belt_finish_and_recall_on_submit in tests/tests/wgpu-validation/util.rs, mirroring the existing staging_belt_random_test but using the new method and omitting the explicit recall() call. The test exercises 100 submission batches and verifies the belt continues to recycle chunks correctly.

Squash or Rebase?

Single commit — ready to rebase onto trunk as-is.

Checklist

  • I self-reviewed and fully understand this PR.
  • WebGPU implementations built with wgpu may be affected behaviorally.
  • Validation and feature gates are in place to confine behavioral changes.
  • Tests demonstrate the validation and altered logic works.
  • CHANGELOG.md entries for the user-facing effects of this change are present.
  • The PR is minimal, and doesn't make sense to land as multiple PRs.
  • Commits are logically scoped and individually reviewable.
  • The PR description has enough context to understand the motivation and solution implemented.

@ruihe774 ruihe774 marked this pull request as ready for review May 5, 2026 06:38
Comment thread wgpu/src/util/belt.rs
Comment on lines +289 to +291
/// the next call that needs free staging-belt chunks. If the encoder is
/// never submitted, the belt's closed chunks will not be returned and the
/// belt will allocate new buffers indefinitely.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems sketchy to me no? Is calling this and then not submitting the encoder just a guaranteed memory leak?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It just does not provide more guarantee than finish; the semantic is similar. If finish is called without recall, the memory is leaked as well. Actually, finish_and_recall_on_submit is relatively safer as it's rarer to forget to submit a CommandEncoder than forgetting to call recall after submission.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is called without recall, surely you can still recall the memory later right? Is this any different? I may have misread your comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. And for finish_and_recall_on_submit, if it is called without Queue::submit, surely you can still recall the memory by submitting the CommandEncoder. The guarantee is just similar: for finish, reclaim is on recall; for this, reclaim is on submission. An edge case may be you encode commands but never submit them and deliberately drop them; but it's rare and in that case you can just use finish

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ruihe774 So then if you call recall on a command encoder that doesn't get submitted, you can never reclaim that memory without destroying the StagingBelt? Thats probably fine I guess

Copy link
Copy Markdown
Author

@ruihe774 ruihe774 May 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be:

if you call finish_and_recall_on_submit on a command encoder that doesn't get submitted, you can never reclaim that memory without destroying the StagingBelt

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume the same would happen if you drop the command encoder before submitting it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Dropped CommandEncoder never gets submitted. The name of this method explicitly states that: recall on submit

Copy link
Copy Markdown
Collaborator

@inner-daemons inner-daemons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little slow but this LGTM

Copy link
Copy Markdown
Collaborator

@kpreid kpreid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[GitHub is giving me internal errors when I try to add file comments, so you get this unassociated comment instead.]

I would suggest, instead of making a copy of the existing staging_belt_random_test, putting the logic in one function called by two test functions, like

fn staging_belt_random_test(use_recall_on_submit: bool) {
    ...
    if use_recall_on_submit {
        belt.finish_and_recall_on_submit(&encoder);
        queue.submit([encoder.finish()]);
        // No explicit recall() needed.
    } else {
        belt.finish();
        queue.submit([encoder.finish()]);
        belt.recall();
    }
    ...
}

#[test]
fn staging_belt_manual_recall() {
    staging_belt_random_test(false);
}

#[test]
fn staging_belt_finish_and_recall_on_submit() {
    staging_belt_random_test(true);
}

My experience is that a very common maintenance error is to modify a test (e.g. to strengthen or weaken an assertion) and not modify other similar tests, so I’d like to keep the rest of this code un-duplicated.

Convenience that combines `finish` and `recall` by deferring the buffer
re-map via `CommandEncoder::map_buffer_on_submit`, so callers no longer
need an explicit `recall()` after submission.
@ruihe774 ruihe774 requested a review from kpreid May 7, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants