pub struct CpuWriteGpuReadBelt {
    chunk_size: u64,
    active_chunks: Vec<Chunk>,
    closed_chunks: Vec<Chunk>,
    free_chunks: Vec<Chunk>,
    sender: Sender<Chunk>,
    receiver: Receiver<Chunk>,
}
Expand description

Efficiently performs many buffer writes by sharing and reusing temporary buffers.

Internally it uses a ring-buffer of staging buffers that are sub-allocated.

Based on to wgpu::util::StagingBelt However, there are some important differences:

  • can create buffers without yet knowing the target copy location
  • lifetime of returned buffers is independent of the CpuWriteGpuReadBelt (allows working with several in parallel!)
  • use of re_renderer’s resource pool
  • handles alignment in a defined manner (see this as of writing open wgpu issue on Alignment guarantees for mapped buffers)

Fields§

§chunk_size: u64

Minimum size for new buffers.

§active_chunks: Vec<Chunk>

Chunks which are CPU write at the moment.

§closed_chunks: Vec<Chunk>

Chunks which are GPU read at the moment.

I.e. they have scheduled transfers already; they are unmapped and one or more command encoder has one or more copy_buffer_to_buffer commands with them as source.

§free_chunks: Vec<Chunk>

Chunks that are back from the GPU and ready to be mapped for write and put into active_chunks.

§sender: Sender<Chunk>

When closed chunks are mapped again, the map callback sends them here.

Note that we shouldn’t use SyncSender since this can block the Sender if a buffer is full, which means that in a single threaded situation (Web!) we might deadlock.

§receiver: Receiver<Chunk>

Free chunks are received here to be put on self.free_chunks.

Implementations§

source§

impl CpuWriteGpuReadBelt

source

const MIN_OFFSET_ALIGNMENT: u64 = 16u64

All allocations of this allocator will be aligned to at least this size.

Requiring a minimum alignment means we need to pad less often. Also, it has the potential of making memcpy operations faster.

Needs to be larger or equal than [wgpu::MAP_ALIGNMENT], [wgpu::COPY_BUFFER_ALIGNMENT] and the largest possible texel block footprint (since offsets for texture copies require this)

For alignment requirements in WebGPU in general, refer to the specification on alignment-class limitations

Note that this does NOT mean that the CPU memory has any alignment. See this issue about lack of CPU memory alignment in wgpu/WebGPU.

source

pub fn new(chunk_size: BufferSize) -> Self

Create a cpu-write & gpu-read staging belt.

The chunk_size is the unit of internal buffer allocation; writes will be sub-allocated within each chunk. Therefore, for optimal use of memory, the chunk size should be:

TODO(andreas): Adaptive chunk sizes TODO(andreas): Shrinking after usage spikes?

source

pub fn allocate<T: Pod + Send + Sync>( &mut self, device: &Device, buffer_pool: &GpuBufferPool, num_elements: usize ) -> Result<CpuWriteGpuReadBuffer<T>, CpuWriteGpuReadError>

Allocates a cpu writable buffer for num_elements instances of type T.

The buffer will be aligned to T’s alignment, but no less than Self::MIN_OFFSET_ALIGNMENT.

source

pub fn before_queue_submit(&mut self)

Prepare currently mapped buffers for use in a submission.

This must be called before the command encoder(s) used in CpuWriteGpuReadBuffer copy operations are submitted.

At this point, all the partially used staging buffers are closed (cannot be used for further writes) until after CpuWriteGpuReadBelt::after_queue_submit is called and the GPU is done copying the data from them.

source

pub fn after_queue_submit(&mut self)

Recall all of the closed buffers back to be reused.

This must only be called after the command encoder(s) used in CpuWriteGpuReadBuffer copy operations are submitted. Additional calls are harmless. Not calling this as soon as possible may result in increased buffer memory usage.

source

fn receive_chunks(&mut self)

Move all chunks that the GPU is done with (and are now mapped again) from self.receiver to self.free_chunks.

Trait Implementations§

source§

impl Debug for CpuWriteGpuReadBelt

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<T> To for T
where T: ?Sized,

§

fn to<T>(self) -> T
where Self: Into<T>,

Converts to T by calling Into<T>::into.
§

fn try_to<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Tries to convert to T by calling TryInto<T>::try_into.
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> WasmNotSend for T
where T: Send,