Skip to content

The structNode does not respect WebGPU memory layout #30983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
holtsetio opened this issue Apr 23, 2025 · 2 comments · Fixed by #31146
Closed

The structNode does not respect WebGPU memory layout #30983

holtsetio opened this issue Apr 23, 2025 · 2 comments · Fixed by #31146
Labels
Enhancement TSL Three.js Shading Language WebGPU
Milestone

Comments

@holtsetio
Copy link
Contributor

holtsetio commented Apr 23, 2025

Description

Consider this simple struct:

const testStruct = struct({
  a: { type: "vec3" },
  b: { type: "vec3" },
});

Because of the WebGPU data memory layout restrictions, vec3 elements have to be aligned to a multiple of 16 bytes in memory. So the correct size of the above struct in memory is 32 bytes. However the structTypeNode gives a length of 6 elements = 24 bytes, so 8 bytes short. In consequence, when creating instancedArrays with this struct, not enough memory is allocated on the GPU for the array.

See attached fiddle for an example, where an array of length 2 is created, but the second element is cut off in memory.

Right now a workaround is to do the alignment calculations manually and pass a TypedArray of the correct size when creating the instancedArray.

Live example

Version

r175-dev

@Spiri0
Copy link
Contributor

Spiri0 commented Apr 23, 2025

There's no automatic detection for neccessary memory setup yet. The structs are still very new. I've always created the buffers manually using the StorageBufferAttribute. When using more complex structs with scalars and vec2, vec3, vec4, and matrices one have to reserve the 16 bytes for each value or matrix column, as you correctly identified.
An extension that checks the struct and then automatically allocates the buffer correctly would certainly be very useful for many users. It just shouldn't interfere with manual buffer setup, otherwise nothing will work for me.
But I think the instancedArray node would be very well suited for such an extension. That certainly makes sense.

This can be a nice example for the threejs examples

const testStruct = struct({
  a: { type: "uint" },
  b: { type: "int" },
  c: { type: "float" },
  d: { type: "vec2" },
  e: { type: "vec3" },
  f: { type: "vec4" },
  g: { type: "mat2" },
  h: { type: "mat3" },
  i: { type: "mat4" },
  j: { type: "bool" }
});

@holtsetio
Copy link
Contributor Author

holtsetio commented May 22, 2025

@sunag Unfortunately this bug still persists, even when ensuring 4 element alignment. Consider for example a struct that contains 4 vec3 members. The struct will occupy 4*4*4 = 64 bytes in memory, however with this fix only 48 bytes will be allocated. At least we should add a warning in the docs for struct() for now, because the resulting bugs can be really nasty and hard to pinpoint, since webgpu just fails silently when trying to access out of bound memory in compute shaders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement TSL Three.js Shading Language WebGPU
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants