I have just recently started learning about how to compute on a GPU and I have decided to start with WGPU as I'm familiar with rust and it can be run on pretty much every GPU. As far as my current understanding goes first I have to create a buffer that is accessible to my CPU, which I have done with the following code.
let array_buffer = device.create_buffer(&wgpu::BufferDescriptor{
label: Some("gpu_test"),
size: (arr.len() * std::mem::size_of::<[i32; 5]>()) as u64,
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
mapped_at_creation: false,
});
After that I have wrote some random data to this buffer with the following line.
queue.write_buffer(&array_buffer, 0, &[1,2,3,4]);
As of right now I have no errors but the problem appears when I now want to read the data in this buffer, there is no example of how to read the data off a buffer in wgpu docs and I didn't see one in webGPU docs too.
In addition how do I know if the buffer is accessible on CPU or GPU webGPU docs talk about it but they don't have an explicate example of how to define a buffer for each one.
First, in order to be able to read a buffer, it must have BufferUsages::MAP_READ
. You've already done that. If you wanted to read a buffer that can't have that usage, you'd need to copy data to a temporary buffer first.
Given that prerequisite, the steps are:
BufferView::map_async()
Device::poll()
map_async()
callback has been called with a successful Result
BufferView::get_mapped_range()
Here's the code I've used for that, which maps the buffer in the variable temp_buffer
:
let (sender, receiver) = futures_channel::oneshot::channel();
temp_buffer
.slice(..)
.map_async(wgpu::MapMode::Read, |result| {
let _ = sender.send(result);
});
device.poll(wgpu::Maintain::Wait); // TODO: poll in the background instead of blocking
receiver
.await
.expect("communication failed")
.expect("buffer reading failed");
let slice: &[u8] = &temp_buffer.slice(..).get_mapped_range();
Note that as per the TODO, this particular code is a work in progress halfway between two sensible states:
channel
, just a OnceCell
because the message will always have arrived when poll(Maintain::Wait)
returns.poll(Maintain::Poll)
or Queue::submit()
repeatedly in the background to trigger checking for completion and thus the callback.