Skip to content

Commit 347c10d

Browse files
authored
Merge pull request #8724 from processing/fix/update-storage-swizzle
Fix swizzle assignment for array element properties in compute shaders
2 parents 9498619 + a39b9e3 commit 347c10d

6 files changed

Lines changed: 110 additions & 1 deletion

File tree

src/strands/ir_builders.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,28 @@ export function createStructArrayElementProxy(strandsContext, bufferNode, indexN
689689
});
690690
const id = DAG.getOrCreateNode(dag, nodeData);
691691
CFG.recordInBasicBlock(cfg, cfg.currentBlock, id);
692-
return createStrandsNode(id, field.dim, strandsContext);
692+
// When a swizzle assignment fires (e.g. buf[i].vel.y *= -1), onRebind
693+
// receives the new vector ID and writes it back to the buffer field,
694+
// equivalent to buf[i].vel = newVec.
695+
const onRebind = (newFieldID) => {
696+
const accessData = DAG.createNodeData({
697+
nodeType: NodeType.OPERATION,
698+
opCode: OpCode.Binary.ARRAY_ACCESS,
699+
dependsOn: [bufferNode.id, index.id],
700+
dimension: field.dim,
701+
baseType: BaseType.FLOAT,
702+
identifier: field.name,
703+
});
704+
const accessID = DAG.getOrCreateNode(dag, accessData);
705+
const assignData = DAG.createNodeData({
706+
nodeType: NodeType.ASSIGNMENT,
707+
dependsOn: [accessID, newFieldID],
708+
phiBlocks: [],
709+
});
710+
const assignID = DAG.getOrCreateNode(dag, assignData);
711+
CFG.recordInBasicBlock(cfg, cfg.currentBlock, assignID);
712+
};
713+
return createStrandsNode(id, field.dim, strandsContext, onRebind);
693714
},
694715
set(val) {
695716
// Create access node as assignment target (field name in identifier)

test/unit/visual/cases/webgpu.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,88 @@ visualSuite("WebGPU", function () {
14221422
await screenshot();
14231423
}
14241424
);
1425+
1426+
visualTest(
1427+
'Compute shader assigns to a swizzle of a struct vector field',
1428+
async function(p5, screenshot) {
1429+
await p5.createCanvas(50, 50, p5.WEBGPU);
1430+
1431+
const particles = p5.createStorage([
1432+
{ position: [15, 10] },
1433+
]);
1434+
1435+
// Negate position.y via swizzle assignment
1436+
const computeShader = p5.buildComputeShader(() => {
1437+
const buf = p5.uniformStorage('buf', particles);
1438+
const idx = p5.index.x;
1439+
buf[idx].position.y *= -1;
1440+
}, { p5, particles });
1441+
p5.compute(computeShader, 1);
1442+
1443+
const sphereShader = p5.baseMaterialShader().modify(() => {
1444+
const buf = p5.uniformStorage('buf', particles);
1445+
p5.getWorldInputs((inputs) => {
1446+
const pos = buf[0].position;
1447+
inputs.position.x += pos.x;
1448+
inputs.position.y += pos.y;
1449+
return inputs;
1450+
});
1451+
}, { p5, particles });
1452+
1453+
const geo = p5.buildGeometry(() => p5.sphere(5));
1454+
p5.background(200);
1455+
p5.noStroke();
1456+
p5.fill(255, 0, 0);
1457+
p5.shader(sphereShader);
1458+
p5.model(geo, 1);
1459+
1460+
await screenshot();
1461+
}
1462+
);
1463+
1464+
visualTest(
1465+
'Compute shader assigns to a swizzle of a struct vector field inside an if statement',
1466+
async function(p5, screenshot) {
1467+
await p5.createCanvas(50, 50, p5.WEBGPU);
1468+
1469+
const particles = p5.createStorage([
1470+
{ position: [0, 0], velocity: [5, 5] },
1471+
]);
1472+
1473+
// Move by velocity, then negate velocity.y if position.y > 0.
1474+
// After 1st run: position=[5,5], velocity=[5,-5].
1475+
// After 2nd run: position=[10,0], velocity=[5,-5].
1476+
const computeShader = p5.buildComputeShader(() => {
1477+
const buf = p5.uniformStorage('buf', particles);
1478+
const idx = p5.index.x;
1479+
buf[idx].position += buf[idx].velocity;
1480+
if (buf[idx].position.y > 0) {
1481+
buf[idx].velocity.y *= -1;
1482+
}
1483+
}, { p5, particles });
1484+
p5.compute(computeShader, 1);
1485+
p5.compute(computeShader, 1);
1486+
1487+
const sphereShader = p5.baseMaterialShader().modify(() => {
1488+
const buf = p5.uniformStorage('buf', particles);
1489+
p5.getWorldInputs((inputs) => {
1490+
const pos = buf[0].position;
1491+
inputs.position.x += pos.x;
1492+
inputs.position.y += pos.y;
1493+
return inputs;
1494+
});
1495+
}, { p5, particles });
1496+
1497+
const geo = p5.buildGeometry(() => p5.sphere(5));
1498+
p5.background(200);
1499+
p5.noStroke();
1500+
p5.fill(255, 0, 0);
1501+
p5.shader(sphereShader);
1502+
p5.model(geo, 1);
1503+
1504+
await screenshot();
1505+
}
1506+
);
14251507
});
14261508

14271509
visualSuite('Feedback', function() {
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"numScreenshots": 1
3+
}
390 Bytes
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"numScreenshots": 1
3+
}

0 commit comments

Comments
 (0)