使用Bevy 0.12计算着色器时遇缓冲区越界错误求助
问题:Bevy 0.12 + bevy_app_compute 实现数组相加时出现wgpu验证错误
运行时触发如下panic:
thread 'Compute Task Pool (6)' panicked at C:\Users\bramb\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wgpu-0.17.2\src\backend\direct.rs:3056:5: wgpu error: Validation Error Caused by: In Queue::write_buffer Copy of 0..32 would end up overrunning the bounds of the Destination buffer of size 16
Rust代码
// calc_gpu_things每帧执行 fn calc_gpu_things(mut compute_worker: ResMut<AppComputeWorker<SimpleComputeWorker>>) { if !compute_worker.ready() { return; }; compute_worker.write("firstArray", &[2.0, 3.0, 4.0, 5.0]); compute_worker.write("secondArray", &[2.0, 3.0, 4.0, 5.0]); let result: [f32; 4] = compute_worker.read("resultArray"); println!("got {:?}", result); } #[derive(TypeUuid)] #[uuid = "2545ae14-a9bc-4f03-9ea4-4eb43d1075a7"] struct SimpleShader; impl ComputeShader for SimpleShader { fn shader() -> ShaderRef { "compute1.wgsl".into() } } #[derive(Resource)] struct SimpleComputeWorker; impl ComputeWorker for SimpleComputeWorker { fn build(world: &mut World) -> AppComputeWorker<Self> { let worker = AppComputeWorkerBuilder::new(world) // Add a staging buffer, it will be available from // both CPU and GPU land. .add_staging("firstArray", &[2.0, 3.0, 4.0, 5.0]) .add_staging("secondArray", &[2.0, 3.0, 4.0, 5.0]) .add_staging("resultArray", &[0.0, 0.0, 0.0, 0.0]) // Create a compute pass from your compute shader // and define used variables .add_pass::<SimpleShader>([1, 1, 1], &["firstArray", "secondArray", "resultArray"]) .build(); worker } }
WGSLL着色器代码
@group(0) @binding(0) var<storage,read> firstArray: array<f32>; @group(0) @binding(1) var<storage,read> secondArray: array<f32>; @group(0) @binding(2) var<storage,read_write> resultArray: array<f32>; @compute @workgroup_size(1, 1, 1) fn main(@builtin(global_invocation_id) global_id: vec3<u32>) { let index: u32 = global_id.x; resultArray[index] = firstArray[index] + secondArray[index]; }
解决方案
1. 修复缓冲区写入的类型不匹配问题
错误根源是Rust字面量类型推断错误:2.0默认是f64类型(单元素8字节),而你初始化缓冲区时用的是f32(单元素4字节),导致write时传入的4个f64总字节数(32)超过缓冲区容量(16)。
修改write方法的参数,明确标注为f32类型:
compute_worker.write("firstArray", &[2.0f32, 3.0f32, 4.0f32, 5.0f32]); compute_worker.write("secondArray", &[2.0f32, 3.0f32, 4.0f32, 5.0f32]);
2. 修复计算着色器仅处理单个元素的问题
当前配置仅启动1个工作线程,只会处理数组的第0个元素,其余3个元素不会被计算。可以通过以下两种方式调整线程数量:
方法一:调整工作组数量
在add_pass中将工作组数量设为[4, 1, 1],总线程数变为4:
.add_pass::<SimpleShader>([4, 1, 1], &["firstArray", "secondArray", "resultArray"])
方法二:调整工作组内线程数
修改着色器的workgroup_size为4, 1, 1,保持工作组数量为[1, 1, 1]:
@compute @workgroup_size(4, 1, 1) fn main(@builtin(global_invocation_id) global_id: vec3<u32>) { let index: u32 = global_id.x; resultArray[index] = firstArray[index] + secondArray[index]; }
两种方法都能让计算着色器覆盖数组所有4个元素,返回正确的相加结果。
内容的提问来源于stack exchange,提问作者NewUser69420
相关产品推荐
相关产品推荐

