rust - write_buffer 不写入缓冲区而是输出零 WGPU

标签 rust webgpu wgpu-rs

您好,我最近开始使用 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() .

必要的更改是:

  1. mapped_at_creation: true 更改为 false,因为您实际上并未使用它。 (如果您愿意,您可以使用该映射来代替 write_buffer() 调用,但比 DeviceExt::create_buffer_init() 更简单。)
  2. 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/

相关文章:

过时的教程之后出现 WebGPU WGLSL 错误 : "access mode ' write' is not valid for the 'storage' address space"

javascript - 如何在 2022 年秋季在 Firefox Nightly 中试用 webGPU?

javascript - 无法读取 null 的属性 'requestDevice'

rust - wgpu 计算直接写入表面纹理 View

rust - 清除前设置剪刀矩形

rust - 如何从 Pin<Arc<Mutex<T>>> 中获取 Pin<&mut T>

rust - Rust编译器不希望有可变引用,而应该有可变引用

rust - 为什么Rust似乎忽略了我的一生注释?

reference - 在 Rust 中,为什么 std::iter::Iterator 的 min 函数返回一个引用?

vector - 获取向量的最后一个元素并将其推送到同一个向量