gfx-rs/wgpu-rs

How to properly write to a buffer every frame?

nikitablack opened this issue · 0 comments

Hello. I came from the Vulkan World and try to map wgpu to it. Unfortunately, it doesn't map 1:1. I can't even create a mapped buffer and copy data to it. Here's how I'm creating a buffer:

let storage_buffer = device.create_buffer(&wgpu::BufferDescriptor {
    label: Some("storage buffer"),
    size: 1000,
    usage: wgpu::BufferUsage::STORAGE
           | wgpu::BufferUsage::COPY_DST
           | wgpu::BufferUsage::MAP_WRITE,
     mapped_at_creation: true,
});

And it fails with the error:

Caused by:
    In Device::create_buffer
      note: label = `storage buffer`
    `MAP` usage can only be combined with the opposite `COPY`, requested MAP_WRITE | COPY_DST | STORAGE

It's confusing. Looks like I should use another flag. But since I'm creating a buffer for writing to it I'm expecting the usage to be wgpu::BufferUsage::COPY_DST, i.e. the buffer should be a destination for my data. But ok, let me try with different flags:

let storage_buffer = device.create_buffer(&wgpu::BufferDescriptor {
    label: Some("storage buffer"),
    size: 1000,
    usage: wgpu::BufferUsage::STORAGE
           | wgpu::BufferUsage::COPY_SRC // CHANGED
           | wgpu::BufferUsage::MAP_WRITE,
     mapped_at_creation: true,
});

But it still fails:

Caused by:
    In Device::create_buffer
      note: label = `storage buffer`
    `MAP` usage can only be combined with the opposite `COPY`, requested MAP_WRITE | COPY_SRC | STORAGE

What am I doing wrong?

Also, I couldn't find any guidelines regarding per-frame buffer updates. In Vulkan it's common to have multiple buffers in flight and update one that is not in use by GPU at the moment. I can't find something similar in wgpu. The only thing I saw in tutorials is to use wgpu::Buffer::map_write which returns a future. So it will block when I'll try to copy into it? Another approach is to use wgpu::Queue::write_buffer. It is even mentioned that the method is intended to have low-performance costs. But I don't understand how - I can't write to the buffer without knowing it's not used by GPU. How does the queue know that? Does wait for the previous frame completion? But in that case, it blocks and we can't say it is "low-performance".

Basically I need to copy a big amount of data every frame and I'm searching for the fastest way. So it would be great if someone could provide best practices regarding this topic.