croraf
croraf

Reputation: 4720

Use input and output buffers in Vulkan compute pipeline

I'm new to Vulkan and graphics programming. I'm using vulkano Rust library https://github.com/vulkano-rs/vulkano (v0.17).

I want to use a compute pipeline to calculate something on a large set of circles. Circles are described as an input tuple (x, y). 2048 of them at the moment. I will make a calculation on them and output 2048 booleans depending on the outcome.

I use one buffer for inputted circles, and the other buffer for the outputted booleans.

At first I just want to make the output to be all trues.

let data_in_iter = (0..2048).map(|i| (i, i));
    let data_in_buffer =
        CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_in_iter)
            .expect("failed to create buffer");

    let data_out_iter = (0..2048).map(|_| false);
    let data_out_buffer =
        CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_out_iter)
            .expect("failed to create buffer");

    let compute_pipeline = Arc::new({
        mod cs {
            vulkano_shaders::shader! {
                ty: "compute",
                src:
                "
                    #version 450

                    layout(local_size_x = 1024, local_size_y = 1, local_size_z = 1) in;

                    layout(set = 0, binding = 0) buffer DataIn {
                        uvec2 data[];
                    } buf_in;

                    layout(set = 0, binding = 1) buffer DataOut {
                        bool data[];
                    } buf_out;

                    void main() {
                        uint idx = gl_GlobalInvocationID.x;
                        buf_out.data[idx] = true /* buf_in.data[idx].x + buf_in.data[idx].y < 2048 */;
                    }
                "
            }
        }
        let shader = cs::Shader::load(device.clone()).expect("failed to create shader module");
        ComputePipeline::new(device.clone(), &shader.main_entry_point(), &())
            .expect("failed to create compute pipeline")
    });

    let layout = compute_pipeline.layout().descriptor_set_layout(0).unwrap();
    let set = Arc::new(
        PersistentDescriptorSet::start(layout.clone())
            .add_buffer(data_in_buffer.clone())
            .unwrap()
            .add_buffer(data_out_buffer.clone())
            .unwrap()
            .build()
            .unwrap(),
    );

    let command_buffer =
        AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
            .unwrap()
            .dispatch([2, 1, 1], compute_pipeline.clone(), set.clone(), ())
            .unwrap()
            .build()
            .unwrap();

    let future = sync::now(device.clone())
        .then_execute(queue.clone(), command_buffer)
        .unwrap()
        .then_signal_fence_and_flush()
        .unwrap();

    future.wait(None).unwrap();

    let content = data_out_buffer.read().unwrap();
    for (n, val) in content.iter().enumerate() {
        println!("{} {:?}", n, val);
    }

But the output I get is:

0 true
1 false
2 false
3 false
4 true
5 false
6 false
7 false
8 true
9 false
...
2047 false

Upvotes: 0

Views: 547

Answers (1)

Jesse Hall
Jesse Hall

Reputation: 6787

The default layout for storage buffers requires that each element of an array start at a 16-byte boundary. So what you're seeing is expected: buf_out.data[i] is written starting at byte 16*i in the output buffer.

You can either match that in your host code, or add the std430 modifier inside the layout() for DataOut. Note the same issue will affect DataIn.

Upvotes: 1

Related Questions