您好,我最近开始使用 wgpu 学习计算着色器,并且在弄清楚如何正确地将数据写入缓冲区方面遇到了一些困难。
我使用此代码创建了一个映射到 CPU 的小缓冲区。
let array_buffer = device.create_buffer(&wgpu::BufferDescriptor{
label: Some("gpu_test"),
size: 4,
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
mapped_at_creation: true,
});
我认为这为我提供了一个可以在 CPU 上访问的缓冲区,我现在使用这行代码写入该缓冲区。
queue.write_buffer(&array_buffer, 0, &[1,2,3,4]);
之后我从缓冲区读取数据
let slice = array_buffer.slice(..).get_mapped_range();
println!("{:?}", slice.get(0..4));
我的输出现在是 Some([0, 0, 0, 0])
在阅读文档后,我认为这是正常行为,因为文档说“写入不会立即提交,而是在内部排队在下一次 submit()
调用开始时发生。”
问题是它并没有真正说明如何提交我尝试运行的内容。
queue.write_buffer(&array_buffer, 0, &[1,2,3,4]);
queue.submit([]);
以及 queue.submit();
的几个不同变体,但输出仍然是 Some([0, 0, 0, 0])
所以如果有人能指出我做错了什么,我将非常感激。
复制的完整代码:
use wgpu;
use pollster;
fn main() {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor{
backends: wgpu::Backends::all(),
dx12_shader_compiler: Default::default(),
});
let adapter = pollster::block_on(instance.request_adapter(&Default::default())).unwrap();
// connect to gpu
let (device, queue) = pollster::block_on(adapter.request_device(&Default::default(), None)).unwrap();
let array_buffer = device.create_buffer(&wgpu::BufferDescriptor{
label: Some("gpu_test"),
size: 4,
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
mapped_at_creation: true,
});
queue.write_buffer(&array_buffer, 0, &[1,2,3,4]);
queue.submit([]);
let slice = array_buffer.slice(..).get_mapped_range();
println!("{:?}", slice.get(0..4));
drop(slice);
array_buffer.unmap();
}
最佳答案
您必须在写入缓冲区后映射该缓冲区。你不能只是永久映射一个缓冲区; CPU和GPU必须轮流访问缓冲区。
现在,您正在使用由 mapped_at_creation: true
创建的映射,但该映射仅允许您向其写入数据,或读取数据你是这样写的,所以在这种情况下它总是零。为了读取写入到 GPU 上的数据(例如通过在队列中执行 write_buffer()
命令),您必须在写入后使用 .map_async()
.
必要的更改是:
- 将
mapped_at_creation: true
更改为 false,因为您实际上并未使用它。 (如果您愿意,您可以使用该映射来代替write_buffer()
调用,但比DeviceExt::create_buffer_init()
更简单。) - 在
submit()
之后,添加对map_async()
的调用,然后添加poll(Maintain::Wait)
。然后缓冲区将被映射为读取,您可以读取它。
fn main() {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
dx12_shader_compiler: Default::default(),
});
let adapter = pollster::block_on(instance.request_adapter(&Default::default())).unwrap();
// connect to gpu
let (device, queue) =
pollster::block_on(adapter.request_device(&Default::default(), None)).unwrap();
let array_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("gpu_test"),
size: 4,
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
mapped_at_creation: false,
});
queue.write_buffer(&array_buffer, 0, &[1, 2, 3, 4]);
queue.submit([]);
array_buffer
.slice(..)
.map_async(wgpu::MapMode::Read, |result| {
// In a real program this should be a message channel of some sort.
// Unwrapping here will, if it fails, panic in whichever thread next
// calls poll(), which isn't good error handling.
result.unwrap();
});
device.poll(wgpu::Maintain::Wait);
let slice = array_buffer.slice(..).get_mapped_range();
println!("{:?}", slice.get(0..4));
drop(slice);
array_buffer.unmap();
}
输出:
Some([1, 2, 3, 4])
关于rust - write_buffer 不写入缓冲区而是输出零 WGPU,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76845027/