Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/strands/ir_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const NodeType = {
ASSIGNMENT: 'assignment',
};
export const INSTANCE_ID_VARYING_NAME = '_p5_instanceID';
export const HOOK_PARAM_PREFIX = '_p5_param_';
export const NodeTypeToName = Object.fromEntries(
Object.entries(NodeType).map(([key, val]) => [val, key])
);
Expand Down
9 changes: 5 additions & 4 deletions src/strands/strands_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
OpCode,
StatementType,
NodeType,
HOOK_PARAM_PREFIX,
// isNativeType
} from './ir_types'
import { strandsBuiltinFunctions } from './strands_builtins'
Expand Down Expand Up @@ -647,7 +648,7 @@ function createHookArguments(strandsContext, parameters){
for (const param of parameters) {
if(isStructType(param.type)) {
const structTypeInfo = structType(param);
const { id, dimension } = build.structInstanceNode(strandsContext, structTypeInfo, param.name, []);
const { id, dimension } = build.structInstanceNode(strandsContext, structTypeInfo, `${HOOK_PARAM_PREFIX}${param.name}`, []);
const structNode = createStrandsNode(id, dimension, strandsContext).withStructProperties(
structTypeInfo.properties.map(prop => prop.name)
);
Expand All @@ -660,7 +661,7 @@ function createHookArguments(strandsContext, parameters){
const oldDeps = dag.dependsOn[structNode.id];
const newDeps = oldDeps.slice();
newDeps[i] = newFieldID;
const rebuilt = build.structInstanceNode(strandsContext, structTypeInfo, param.name, newDeps);
const rebuilt = build.structInstanceNode(strandsContext, structTypeInfo, `${HOOK_PARAM_PREFIX}${param.name}`, newDeps);
structNode.id = rebuilt.id;
};
// TODO: implement member access operations
Expand All @@ -681,7 +682,7 @@ function createHookArguments(strandsContext, parameters){
newValueID = newVal.id;
}
newDependsOn[i] = newValueID;
const newStructInfo = build.structInstanceNode(strandsContext, structTypeInfo, param.name, newDependsOn);
const newStructInfo = build.structInstanceNode(strandsContext, structTypeInfo, `${HOOK_PARAM_PREFIX}${param.name}`, newDependsOn);
structNode.id = newStructInfo.id;
}
})
Expand All @@ -697,7 +698,7 @@ function createHookArguments(strandsContext, parameters){
throw new Error(`Missing dataType for parameter ${param.name} of type ${param.type.typeName}`);
}
const typeInfo = param.type.dataType;
const { id, dimension } = build.variableNode(strandsContext, typeInfo, param.name);
const { id, dimension } = build.variableNode(strandsContext, typeInfo, `${HOOK_PARAM_PREFIX}${param.name}`);
const arg = createStrandsNode(id, dimension, strandsContext);
args.push(arg);
}
Expand Down
4 changes: 2 additions & 2 deletions src/webgl/strands_glslBackend.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import noiseGLSL from './shaders/functions/noise3DGLSL.glsl';
import randomGLSL from './shaders/functions/randomGLSL.glsl';
import randomVertGLSL from './shaders/functions/randomVertGLSL.glsl';
import { NodeType, OpCodeToSymbol, BlockType, OpCode, NodeTypeToName, isStructType, BaseType, StatementType, DataType, INSTANCE_ID_VARYING_NAME } from "../strands/ir_types";
import { NodeType, OpCodeToSymbol, BlockType, OpCode, NodeTypeToName, isStructType, BaseType, StatementType, DataType, INSTANCE_ID_VARYING_NAME, HOOK_PARAM_PREFIX } from "../strands/ir_types";
import { getNodeDataFromID, extractNodeTypeInfo } from "../strands/ir_dag";
import * as FES from '../strands/strands_FES';
import * as build from '../strands/ir_builders';
Expand Down Expand Up @@ -168,7 +168,7 @@ const cfgHandlers = {
export const glslBackend = {
hookEntry(hookType) {
const firstLine = `(${hookType.parameters.flatMap((param) => {
return `${param.qualifiers?.length ? param.qualifiers.join(' ') : ''}${param.type.typeName} ${param.name}`;
return `${param.qualifiers?.length ? param.qualifiers.join(' ') : ''}${param.type.typeName} ${HOOK_PARAM_PREFIX}${param.name}`;
}).join(', ')}) {`;
return firstLine;
},
Expand Down
8 changes: 4 additions & 4 deletions src/webgpu/strands_wgslBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import noiseWGSL from './shaders/functions/noise3DWGSL.js';
import randomWGSL from './shaders/functions/randomWGSL';
import randomVertWGSL from './shaders/functions/randomVertWGSL';
import randomComputeWGSL from './shaders/functions/randomComputeWGSL';
import { NodeType, OpCodeToSymbol, BlockType, OpCode, NodeTypeToName, isStructType, BaseType, StatementType, DataType, INSTANCE_ID_VARYING_NAME } from "../strands/ir_types";
import { NodeType, OpCodeToSymbol, BlockType, OpCode, NodeTypeToName, isStructType, BaseType, StatementType, DataType, INSTANCE_ID_VARYING_NAME, HOOK_PARAM_PREFIX } from "../strands/ir_types";
import { getNodeDataFromID, extractNodeTypeInfo } from "../strands/ir_dag";
import * as FES from '../strands/strands_FES';
import * as build from '../strands/ir_builders';
Expand Down Expand Up @@ -190,16 +190,16 @@ export const wgslBackend = {
hookEntry(hookType) {
const params = hookType.parameters.map((param) => {
// For struct types, use a raw prefix since we'll create a mutable copy
const paramName = param.type.properties ? `_p5_strands_raw_${param.name}` : param.name;
const paramName = param.type.properties ? `_p5_strands_raw_${param.name}` : `${HOOK_PARAM_PREFIX}${param.name}`;
return `${paramName}: ${param.type.typeName}`;
}).join(', ');

const firstLine = `(${params}) {`;

// Generate mutable copies for struct parameters with original names
// Generate mutable copies for struct parameters
const mutableCopies = hookType.parameters
.filter(param => param.type.properties) // Only struct types
.map(param => ` var ${param.name} = _p5_strands_raw_${param.name};`)
.map(param => ` var ${HOOK_PARAM_PREFIX}${param.name} = _p5_strands_raw_${param.name};`)
.join('\n');

return mutableCopies ? firstLine + '\n' + mutableCopies : firstLine;
Expand Down
27 changes: 27 additions & 0 deletions test/unit/webgl/p5.RendererGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,33 @@ suite('p5.RendererGL', function() {
});
});

suite('p5.strands', function() {
test('a uniform whose name matches a hook parameter name does not break', function() {
myp5.createCanvas(10, 10, myp5.WEBGL);
myp5.pixelDensity(1);

// 'color' is the GLSL parameter name of the getFinalColor hook's first argument.
// Creating a uniform with the same name used to cause a GLSL name clash.
const myShader = myp5.baseColorShader().modify(() => {
const color = myp5.uniformFloat('color', 0.5);
myp5.finalColor.begin();
myp5.finalColor.set([color, color, color, 1]);
myp5.finalColor.end();
}, { myp5 });

myp5.background(0);
myp5.noStroke();
myp5.shader(myShader);
myp5.plane(myp5.width, myp5.height);

const pixel = myp5.get(5, 5);
assert.approximately(pixel[0], 128, 1);
assert.equal(pixel[0], pixel[1]);
assert.equal(pixel[1], pixel[2]);
assert.equal(pixel[3], 255);
});
});

suite('texture binding', function() {
test('setting a custom texture works', function() {
myp5.createCanvas(10, 10, myp5.WEBGL);
Expand Down
26 changes: 26 additions & 0 deletions test/unit/webgpu/p5.RendererWebGPU.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,4 +321,30 @@ suite('WebGPU p5.RendererWebGPU', function() {
expect(() => buf.set(0, 42)).to.throw();
});
});

suite('p5.strands', function() {
test('a uniform whose name matches a hook parameter name does not break', async function() {
myp5.pixelDensity(1);

// 'color' is the WGSL parameter name of the getFinalColor hook's first argument.
// Creating a uniform with the same name used to cause a WGSL name clash.
const myShader = myp5.baseColorShader().modify(() => {
const color = myp5.uniformFloat('color', 0.5);
myp5.finalColor.begin();
myp5.finalColor.set([color, color, color, 1]);
myp5.finalColor.end();
}, { myp5 });

myp5.background(0);
myp5.noStroke();
myp5.shader(myShader);
myp5.plane(myp5.width, myp5.height);

const pixel = await myp5.get(5, 5);
expect(pixel[0]).to.be.closeTo(128, 1);
expect(pixel[0]).to.equal(pixel[1]);
expect(pixel[1]).to.equal(pixel[2]);
expect(pixel[3]).to.equal(255);
});
});
});
Loading