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

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

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

Fields§

§chunk_size: u64

Minimum size for new buffers.

§active_chunks: Vec<Chunk>

Chunks for which the GPU writes are scheduled, but we haven’t mapped them yet.

§free_chunks: Vec<Chunk>

Chunks that have been unmapped and are ready for writing by the GPU.

§received_chunks: Vec<Chunk>

Chunks that are currently mapped and ready for reading by the CPU.

§sender: Sender<Chunk>

When a chunk mapping is successful, it is moved to this sender to be read by the CPU.

§receiver: Receiver<Chunk>

Chunks are received here are ready to be read by the CPU.

§frame_index: u64

Current frame index, used for keeping track of how old chunks are.

Implementations§

source§

impl GpuReadbackBelt

source

const MIN_ALIGNMENT: u64 = 8u64

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

Buffer mappings however are currently NOT guaranteed to be aligned to this size! See this issue on Alignment guarantees for mapped buffers.

source

pub fn new(chunk_size: BufferSize) -> Self

Create a ring buffer for efficient & easy gpu memory readback.

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

  • larger than the largest single GpuReadbackBelt::allocate operation;
  • 1-4 times less than the total amount of data uploaded per submission
  • bigger is better, within these bounds.

TODO(andreas): Adaptive chunk sizes TODO(andreas): Shrinking after usage spikes (e.g. screenshots of different sizes!)

source

pub fn allocate( &mut self, device: &Device, buffer_pool: &GpuBufferPool, size_in_bytes: BufferAddress, identifier: GpuReadbackIdentifier, user_data: Box<dyn Any + Send + 'static> ) -> GpuReadbackBuffer

Allocates a Gpu writable buffer & cpu readable buffer with a given size.

source

pub fn after_queue_submit(&mut self)

Prepare used buffers for CPU read.

This should be called after the command encoder(s) used in GpuReadbackBuffer copy operations are submitted.

source

pub fn begin_frame(&mut self, frame_index: u64)

Should be called at the beginning of a new frame.

Discards stale data that hasn’t been received by GpuReadbackBelt::readback_data for more than a frame.

source

pub fn readback_data<UserDataType: 'static>( &mut self, identifier: GpuReadbackIdentifier, callback: impl FnOnce(&[u8], Box<UserDataType>) )

Try to receive a pending data readback with the given identifier and the given user data type.

Returns the oldest received data with the given identifier & type. This is almost certainly also the oldest scheduled readback. But there is no strict guarantee for this. It could in theory happen that a readback is scheduled after a previous one, but finishes before it!

ATTENTION: Do NOT assume any alignment on the slice passed to on_data_received. See this issue on Alignment guarantees for mapped buffers.

source

fn receive_chunks(&mut self)

Check if any new chunks are ready to be read.

source

fn reuse_chunk(&mut self, chunk: Chunk)

Trait Implementations§

source§

impl Debug for GpuReadbackBelt

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,