Struct bevy::render::render_resource::BufferSlice
pub struct BufferSlice<'a> { /* private fields */ }
Implementations§
Methods from Deref<Target = BufferSlice<'a>>§
pub fn map_async(
&self,
mode: MapMode,
callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static
)
pub fn map_async( &self, mode: MapMode, callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static )
Map the buffer. Buffer is ready to map once the callback is called.
For the callback to complete, either queue.submit(..)
, instance.poll_all(..)
, or device.poll(..)
must be called elsewhere in the runtime, possibly integrated into an event loop or run on a separate thread.
The callback will be called on the thread that first calls the above functions after the gpu work has completed. There are no restrictions on the code you can run in the callback, however on native the call to the function will not complete until the callback returns, so prefer keeping callbacks short and used to set flags, send messages, etc.
Examples found in repository?
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
fn map_and_read_buffer(
render_device: Res<RenderDevice>,
buffers: Res<Buffers>,
sender: Res<RenderWorldSender>,
) {
// Finally time to get our data back from the gpu.
// First we get a buffer slice which represents a chunk of the buffer (which we
// can't access yet).
// We want the whole thing so use unbounded range.
let buffer_slice = buffers.cpu_buffer.slice(..);
// Now things get complicated. WebGPU, for safety reasons, only allows either the GPU
// or CPU to access a buffer's contents at a time. We need to "map" the buffer which means
// flipping ownership of the buffer over to the CPU and making access legal. We do this
// with `BufferSlice::map_async`.
//
// The problem is that map_async is not an async function so we can't await it. What
// we need to do instead is pass in a closure that will be executed when the slice is
// either mapped or the mapping has failed.
//
// The problem with this is that we don't have a reliable way to wait in the main
// code for the buffer to be mapped and even worse, calling get_mapped_range or
// get_mapped_range_mut prematurely will cause a panic, not return an error.
//
// Using channels solves this as awaiting the receiving of a message from
// the passed closure will force the outside code to wait. It also doesn't hurt
// if the closure finishes before the outside code catches up as the message is
// buffered and receiving will just pick that up.
//
// It may also be worth noting that although on native, the usage of asynchronous
// channels is wholly unnecessary, for the sake of portability to WASM
// we'll use async channels that work on both native and WASM.
let (s, r) = crossbeam_channel::unbounded::<()>();
// Maps the buffer so it can be read on the cpu
buffer_slice.map_async(MapMode::Read, move |r| match r {
// This will execute once the gpu is ready, so after the call to poll()
Ok(_) => s.send(()).expect("Failed to send map update"),
Err(err) => panic!("Failed to map buffer {err}"),
});
// In order for the mapping to be completed, one of three things must happen.
// One of those can be calling `Device::poll`. This isn't necessary on the web as devices
// are polled automatically but natively, we need to make sure this happens manually.
// `Maintain::Wait` will cause the thread to wait on native but not on WebGpu.
// This blocks until the gpu is done executing everything
render_device.poll(Maintain::wait()).panic_on_timeout();
// This blocks until the buffer is mapped
r.recv().expect("Failed to receive the map_async message");
{
let buffer_view = buffer_slice.get_mapped_range();
let data = buffer_view
.chunks(std::mem::size_of::<u32>())
.map(|chunk| u32::from_ne_bytes(chunk.try_into().expect("should be a u32")))
.collect::<Vec<u32>>();
sender
.send(data)
.expect("Failed to send data to main world");
}
// We need to make sure all `BufferView`'s are dropped before we do what we're about
// to do.
// Unmap so that we can copy to the staging buffer in the next iteration.
buffers.cpu_buffer.unmap();
}
More examples
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
fn receive_image_from_buffer(
image_copiers: Res<ImageCopiers>,
render_device: Res<RenderDevice>,
sender: Res<RenderWorldSender>,
) {
for image_copier in image_copiers.0.iter() {
if !image_copier.enabled() {
continue;
}
// Finally time to get our data back from the gpu.
// First we get a buffer slice which represents a chunk of the buffer (which we
// can't access yet).
// We want the whole thing so use unbounded range.
let buffer_slice = image_copier.buffer.slice(..);
// Now things get complicated. WebGPU, for safety reasons, only allows either the GPU
// or CPU to access a buffer's contents at a time. We need to "map" the buffer which means
// flipping ownership of the buffer over to the CPU and making access legal. We do this
// with `BufferSlice::map_async`.
//
// The problem is that map_async is not an async function so we can't await it. What
// we need to do instead is pass in a closure that will be executed when the slice is
// either mapped or the mapping has failed.
//
// The problem with this is that we don't have a reliable way to wait in the main
// code for the buffer to be mapped and even worse, calling get_mapped_range or
// get_mapped_range_mut prematurely will cause a panic, not return an error.
//
// Using channels solves this as awaiting the receiving of a message from
// the passed closure will force the outside code to wait. It also doesn't hurt
// if the closure finishes before the outside code catches up as the message is
// buffered and receiving will just pick that up.
//
// It may also be worth noting that although on native, the usage of asynchronous
// channels is wholly unnecessary, for the sake of portability to WASM
// we'll use async channels that work on both native and WASM.
let (s, r) = crossbeam_channel::bounded(1);
// Maps the buffer so it can be read on the cpu
buffer_slice.map_async(MapMode::Read, move |r| match r {
// This will execute once the gpu is ready, so after the call to poll()
Ok(r) => s.send(r).expect("Failed to send map update"),
Err(err) => panic!("Failed to map buffer {err}"),
});
// In order for the mapping to be completed, one of three things must happen.
// One of those can be calling `Device::poll`. This isn't necessary on the web as devices
// are polled automatically but natively, we need to make sure this happens manually.
// `Maintain::Wait` will cause the thread to wait on native but not on WebGpu.
// This blocks until the gpu is done executing everything
render_device.poll(Maintain::wait()).panic_on_timeout();
// This blocks until the buffer is mapped
r.recv().expect("Failed to receive the map_async message");
// This could fail on app exit, if Main world clears resources (including receiver) while Render world still renders
let _ = sender.send(buffer_slice.get_mapped_range().to_vec());
// We need to make sure all `BufferView`'s are dropped before we do what we're about
// to do.
// Unmap so that we can copy to the staging buffer in the next iteration.
image_copier.buffer.unmap();
}
}
pub fn get_mapped_range(&self) -> BufferView<'a>
pub fn get_mapped_range(&self) -> BufferView<'a>
Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
through [BufferDescriptor::mapped_at_creation
] or [BufferSlice::map_async
], will panic.
Examples found in repository?
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
fn map_and_read_buffer(
render_device: Res<RenderDevice>,
buffers: Res<Buffers>,
sender: Res<RenderWorldSender>,
) {
// Finally time to get our data back from the gpu.
// First we get a buffer slice which represents a chunk of the buffer (which we
// can't access yet).
// We want the whole thing so use unbounded range.
let buffer_slice = buffers.cpu_buffer.slice(..);
// Now things get complicated. WebGPU, for safety reasons, only allows either the GPU
// or CPU to access a buffer's contents at a time. We need to "map" the buffer which means
// flipping ownership of the buffer over to the CPU and making access legal. We do this
// with `BufferSlice::map_async`.
//
// The problem is that map_async is not an async function so we can't await it. What
// we need to do instead is pass in a closure that will be executed when the slice is
// either mapped or the mapping has failed.
//
// The problem with this is that we don't have a reliable way to wait in the main
// code for the buffer to be mapped and even worse, calling get_mapped_range or
// get_mapped_range_mut prematurely will cause a panic, not return an error.
//
// Using channels solves this as awaiting the receiving of a message from
// the passed closure will force the outside code to wait. It also doesn't hurt
// if the closure finishes before the outside code catches up as the message is
// buffered and receiving will just pick that up.
//
// It may also be worth noting that although on native, the usage of asynchronous
// channels is wholly unnecessary, for the sake of portability to WASM
// we'll use async channels that work on both native and WASM.
let (s, r) = crossbeam_channel::unbounded::<()>();
// Maps the buffer so it can be read on the cpu
buffer_slice.map_async(MapMode::Read, move |r| match r {
// This will execute once the gpu is ready, so after the call to poll()
Ok(_) => s.send(()).expect("Failed to send map update"),
Err(err) => panic!("Failed to map buffer {err}"),
});
// In order for the mapping to be completed, one of three things must happen.
// One of those can be calling `Device::poll`. This isn't necessary on the web as devices
// are polled automatically but natively, we need to make sure this happens manually.
// `Maintain::Wait` will cause the thread to wait on native but not on WebGpu.
// This blocks until the gpu is done executing everything
render_device.poll(Maintain::wait()).panic_on_timeout();
// This blocks until the buffer is mapped
r.recv().expect("Failed to receive the map_async message");
{
let buffer_view = buffer_slice.get_mapped_range();
let data = buffer_view
.chunks(std::mem::size_of::<u32>())
.map(|chunk| u32::from_ne_bytes(chunk.try_into().expect("should be a u32")))
.collect::<Vec<u32>>();
sender
.send(data)
.expect("Failed to send data to main world");
}
// We need to make sure all `BufferView`'s are dropped before we do what we're about
// to do.
// Unmap so that we can copy to the staging buffer in the next iteration.
buffers.cpu_buffer.unmap();
}
More examples
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
fn receive_image_from_buffer(
image_copiers: Res<ImageCopiers>,
render_device: Res<RenderDevice>,
sender: Res<RenderWorldSender>,
) {
for image_copier in image_copiers.0.iter() {
if !image_copier.enabled() {
continue;
}
// Finally time to get our data back from the gpu.
// First we get a buffer slice which represents a chunk of the buffer (which we
// can't access yet).
// We want the whole thing so use unbounded range.
let buffer_slice = image_copier.buffer.slice(..);
// Now things get complicated. WebGPU, for safety reasons, only allows either the GPU
// or CPU to access a buffer's contents at a time. We need to "map" the buffer which means
// flipping ownership of the buffer over to the CPU and making access legal. We do this
// with `BufferSlice::map_async`.
//
// The problem is that map_async is not an async function so we can't await it. What
// we need to do instead is pass in a closure that will be executed when the slice is
// either mapped or the mapping has failed.
//
// The problem with this is that we don't have a reliable way to wait in the main
// code for the buffer to be mapped and even worse, calling get_mapped_range or
// get_mapped_range_mut prematurely will cause a panic, not return an error.
//
// Using channels solves this as awaiting the receiving of a message from
// the passed closure will force the outside code to wait. It also doesn't hurt
// if the closure finishes before the outside code catches up as the message is
// buffered and receiving will just pick that up.
//
// It may also be worth noting that although on native, the usage of asynchronous
// channels is wholly unnecessary, for the sake of portability to WASM
// we'll use async channels that work on both native and WASM.
let (s, r) = crossbeam_channel::bounded(1);
// Maps the buffer so it can be read on the cpu
buffer_slice.map_async(MapMode::Read, move |r| match r {
// This will execute once the gpu is ready, so after the call to poll()
Ok(r) => s.send(r).expect("Failed to send map update"),
Err(err) => panic!("Failed to map buffer {err}"),
});
// In order for the mapping to be completed, one of three things must happen.
// One of those can be calling `Device::poll`. This isn't necessary on the web as devices
// are polled automatically but natively, we need to make sure this happens manually.
// `Maintain::Wait` will cause the thread to wait on native but not on WebGpu.
// This blocks until the gpu is done executing everything
render_device.poll(Maintain::wait()).panic_on_timeout();
// This blocks until the buffer is mapped
r.recv().expect("Failed to receive the map_async message");
// This could fail on app exit, if Main world clears resources (including receiver) while Render world still renders
let _ = sender.send(buffer_slice.get_mapped_range().to_vec());
// We need to make sure all `BufferView`'s are dropped before we do what we're about
// to do.
// Unmap so that we can copy to the staging buffer in the next iteration.
image_copier.buffer.unmap();
}
}
pub fn get_mapped_range_mut(&self) -> BufferViewMut<'a>
pub fn get_mapped_range_mut(&self) -> BufferViewMut<'a>
Synchronously and immediately map a buffer for writing. If the buffer is not immediately mappable
through [BufferDescriptor::mapped_at_creation
] or [BufferSlice::map_async
], will panic.
Trait Implementations§
§impl<'a> Clone for BufferSlice<'a>
impl<'a> Clone for BufferSlice<'a>
§fn clone(&self) -> BufferSlice<'a>
fn clone(&self) -> BufferSlice<'a>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more§impl<'a> Debug for BufferSlice<'a>
impl<'a> Debug for BufferSlice<'a>
§impl<'a> Deref for BufferSlice<'a>
impl<'a> Deref for BufferSlice<'a>
Auto Trait Implementations§
impl<'a> Freeze for BufferSlice<'a>
impl<'a> !RefUnwindSafe for BufferSlice<'a>
impl<'a> Send for BufferSlice<'a>
impl<'a> Sync for BufferSlice<'a>
impl<'a> Unpin for BufferSlice<'a>
impl<'a> !UnwindSafe for BufferSlice<'a>
Blanket Implementations§
§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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