英文:
Creating writing and reading from buffer wgpu
问题
我刚刚开始学习如何在GPU上进行计算,我决定从WGPU开始,因为我熟悉Rust并且它可以在几乎所有的GPU上运行。根据我目前的理解,首先我需要创建一个可以被CPU访问的缓冲区,我已经使用以下代码完成了这一步。
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,
});
之后,我使用以下代码将一些随机数据写入此缓冲区。
queue.write_buffer(&array_buffer, 0, &[1,2,3,4]);
截止目前为止,我没有出现任何错误,但问题出现在我现在想要读取此缓冲区中的数据时,wgpu文档中没有关于如何从缓冲区读取数据的示例,而且我在WebGPU文档中也没有看到相关内容。
此外,我如何知道缓冲区是否可由CPU或GPU访问,WebGPU文档提到了这一点,但没有明确的示例说明如何为每个缓冲区定义它。
英文:
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.
答案1
得分: 2
首先,为了能够读取缓冲区,它必须具有 BufferUsages::MAP_READ
。你已经完成了这一步。如果你想要读取一个不能具有这个用途的缓冲区,你需要首先将数据复制到临时缓冲区。
在具备这个前提条件的情况下,以下是步骤:
- 调用
BufferView::map_async()
- 调用
Device::poll()
- 确认
map_async()
回调已经成功调用,并返回了成功的Result
- 调用
BufferView::get_mapped_range()
以下是我用于执行这些操作的代码,它将缓冲区映射到变量 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();
请注意,根据 TODO 注释,这段特定的代码正处于两种合理状态之间的工作进展中:
- 如果你只打算在缓冲区准备好读取时阻塞,那么你不需要一个
channel
,只需要一个OnceCell
,因为在poll(Maintain::Wait)
返回时消息总是已经到达了。 - 如果你想要真正的异步操作,那么需要有一些东西在后台反复调用
poll(Maintain::Poll)
或Queue::submit()
,以触发检查完成状态和回调的操作。
英文:
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:
- Call
BufferView::map_async()
- Call
Device::poll()
- Confirm that the
map_async()
callback has been called with a successfulResult
- Call
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:
- If you intend only to block on the buffer being ready to read, then you don't need a
channel
, just aOnceCell
because the message will always have arrived whenpoll(Maintain::Wait)
returns. - If you want to be truly async, then something needs to be calling either
poll(Maintain::Poll)
orQueue::submit()
repeatedly in the background to trigger checking for completion and thus the callback.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论