0

我正在尝试遵循Windows 10 上 wgpu 中的“hello compute”示例(进行了一些小的修改,主要是对着色器进行了内脏处理,因此它基本上没有实际计算),但是当我最后读取缓冲区时,它总是归零出去。

这是我要运行的着色器,它编译得很好,我认为它是正确的

[[block]]
struct Numbers
{
    data: [[stride(4)]] array<u32>;
};


[[group(0), binding(0)]]
var<storage, read_write> numbers: Numbers;

[[stage(compute), workgroup_size(1)]]
fn main()
{
    numbers.data[0] = numbers.data[0] + u32(1);
    numbers.data[1] = numbers.data[1] + u32(1);
    numbers.data[2] = numbers.data[2] + u32(1);
}

至于 wgpu 代码,它非常接近教程:

我得到了实例、设备和队列

let instance = Instance::new(Backends::PRIMARY);

let adapter = block_on(instance
    .request_adapter(&RequestAdapterOptions
    {
        power_preference: PowerPreference::default(),
        compatible_surface: None,
    }))
    .unwrap();

let (device, queue) = block_on(adapter
    .request_device(&Default::default(), None))
    .unwrap();

编译着色器并制作管道:

let shader = device.create_shader_module(&ShaderModuleDescriptor
{
    label: Some("shader"),
    source: ShaderSource::Wgsl(shader_src.into()),
});

let pipeline = device.create_compute_pipeline(&ComputePipelineDescriptor
{
    label: None,
    layout: None,
    module: &shader,
    entry_point: "main",
});

制作暂存和存储缓冲区。打印 12,这dbg!(size)对于 4 字节 u32s 的 3 长度数组应该是正确的。

let buffer = [1u32, 2, 3];
let size = std::mem::size_of_val(&buffer) as u64;
dbg!(size);

let staging_buffer = device.create_buffer(&BufferDescriptor
{
    label: None,
    size: size,
    usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
    mapped_at_creation: false,
});

let storage_buffer = device.create_buffer_init(&BufferInitDescriptor
{
    label: Some("storage buffer"),
    contents: cast_slice(&buffer),
    usage: BufferUsages::STORAGE
        | BufferUsages::COPY_DST
        | BufferUsages::COPY_SRC,
});

设置绑定组:

let bg_layout = pipeline.get_bind_group_layout(0);
let bind_group = device.create_bind_group(&BindGroupDescriptor
{
    label: None,
    layout: &bg_layout,
    entries: &[BindGroupEntry
    {
        binding: 0,
        resource: storage_buffer.as_entire_binding(),
    }]
});

获取编码器并创建计算通道。应该将copy_buffer_to_buffer存储缓冲区复制到暂存缓冲区,以便我可以在最后读取它。

let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor
{
    label: None,
});

{
    let mut cpass = encoder.begin_compute_pass(&ComputePassDescriptor
    {
        label: None
    });
    cpass.set_pipeline(&pipeline);
    cpass.set_bind_group(0, &bind_group, &[]);
    cpass.dispatch(1, 1, 1);
}

encoder.copy_buffer_to_buffer(
    &storage_buffer, 0,
    &staging_buffer, 0,
    size);

queue.submit(Some(encoder.finish()));

然后提交计算通行证和结果块:

let buf_slice = staging_buffer.slice(..);
let buf_future = buf_slice.map_async(MapMode::Read);

device.poll(Maintain::Wait);

if let Ok(()) = block_on(buf_future)
{
    let data = buf_slice.get_mapped_range();
    let result = cast_slice::<u8, u32>(&data).to_vec();

    drop(data);
    staging_buffer.unmap();

    println!("{:?}", result);
}
else
{
    println!("error");
}

没有达到错误情况,程序终止时没有错误,但结果总是打印出来[0, 0 ,0],当它应该是[2, 3, 4]

我究竟做错了什么?

4

1 回答 1

0

该程序在我的独立显卡上运行时运行良好,但 wgpu 在我的集成 Intel HD Graphics 630 上出现错误,这就是该程序似乎无法运行的原因。

于 2021-08-31T02:25:28.680 回答