| 436 | `; |
| 437 | |
| 438 | const createCentroidReduceShader = () => ` |
| 439 | struct Params { |
| 440 | inputCount: u32, |
| 441 | } |
| 442 | |
| 443 | @group(0) @binding(0) var<storage, read> inputPartials: array<vec4<u32>>; |
| 444 | @group(0) @binding(1) var<storage, read_write> outputPartials: array<vec4<u32>>; |
| 445 | @group(0) @binding(2) var<uniform> params: Params; |
| 446 | |
| 447 | var<workgroup> partialSums: array<vec4<u32>, ${centroidWorkgroupSize}>; |
| 448 | |
| 449 | fn addPartial(a: vec4<u32>, b: vec4<u32>) -> vec4<u32> { |
| 450 | return vec4<u32>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); |
| 451 | } |
| 452 | |
| 453 | @compute @workgroup_size(${centroidWorkgroupSize}) |
| 454 | fn main( |
| 455 | @builtin(global_invocation_id) globalId: vec3<u32>, |
| 456 | @builtin(local_invocation_id) localId: vec3<u32>, |
| 457 | @builtin(workgroup_id) workgroupId: vec3<u32> |
| 458 | ) { |
| 459 | let index = globalId.x; |
| 460 | var partial = vec4<u32>(0u, 0u, 0u, 0u); |
| 461 | if (index < params.inputCount) { |
| 462 | partial = inputPartials[index]; |
| 463 | } |
| 464 | |
| 465 | partialSums[localId.x] = partial; |
| 466 | workgroupBarrier(); |
| 467 | |
| 468 | var stride = ${centroidWorkgroupSize / 2}u; |
| 469 | loop { |
| 470 | if (localId.x < stride) { |
| 471 | partialSums[localId.x] = addPartial(partialSums[localId.x], partialSums[localId.x + stride]); |
| 472 | } |
| 473 | workgroupBarrier(); |
| 474 | |
| 475 | if (stride == 1u) { |
| 476 | break; |
| 477 | } |
| 478 | stride = stride / 2u; |
| 479 | } |
| 480 | |
| 481 | if (localId.x == 0u) { |
| 482 | outputPartials[workgroupId.x] = partialSums[0]; |
| 483 | } |
| 484 | } |
| 485 | `; |
| 486 | |
| 487 | const centroidComparePipeline = device.createComputePipeline({ |
| 488 | layout: 'auto', |