Skip to content

StructTypeNode: Fix memory length calculations (#32375)#32377

Merged
sunag merged 2 commits into
mrdoob:devfrom
holtsetio:fix-structLengthCalculation
Nov 26, 2025
Merged

StructTypeNode: Fix memory length calculations (#32375)#32377
sunag merged 2 commits into
mrdoob:devfrom
holtsetio:fix-structLengthCalculation

Conversation

@holtsetio

@holtsetio holtsetio commented Nov 26, 2025

Copy link
Copy Markdown
Contributor

Fixed #32375.

Description

This change fixes the memory length calculation for the StructTypeNode so three.js allocates enough memory for custom structs.
I have also renamed the getByteBoundaryFromType() function to getAlignmentFromType() and fixed the values for mat3/mat4 according to https://webgpufundamentals.org/webgpu/lessons/webgpu-memory-layout.html

@github-actions

github-actions Bot commented Nov 26, 2025

Copy link
Copy Markdown

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 350.29
83.05
350.29
83.05
+0 B
+0 B
WebGPU 612.89
170.29
612.89
170.27
+1 B
-17 B
WebGPU Nodes 611.49
170.01
611.49
169.99
+1 B
-13 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 482.23
117.82
482.23
117.82
+0 B
+0 B
WebGPU 683.78
186
683.78
186
+0 B
+0 B
WebGPU Nodes 633.61
173.18
633.61
173.18
+0 B
+0 B

@holtsetio

holtsetio commented Nov 26, 2025

Copy link
Copy Markdown
Contributor Author

Edit: Disregard this, adressed with the next commit!

To note here:
getLength() now returns the length that a buffer with a single object of this struct would occupy in memory.
In some edge cases (examples below), the returned length is too long for buffers with multiple objects of this struct. However, mitigating this is hard with the current code structure and allocating a few bytes too much is definitely better than allocating too little, as it was before..

Examples:

const testStruct = struct({
	a: { type: "vec2" },
	aa: { type: "vec2" },
	aaa: { type: "vec2" },
});

getLength() for this struct now returns 8 (32 bytes), which is correct for a buffer with a single element, e.g. instancedArray(1, testStruct);
However, for instancedArray(2, testStruct); this would result in a length of 2*32=64 bytes, even though this buffer only occupies 48 bytes.

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

getLength() for this struct now returns 4 (16 bytes), which is correct for a buffer with a single element, e.g. instancedArray(1, testStruct);
However, for instancedArray(4, testStruct); this would result in a length of 4*32=128 bytes, even though this buffer only occupies 16 bytes.

Maybe to fully address this, there would need to be a getLength() function that also takes the number of elements of this struct into account?

@holtsetio

holtsetio commented Nov 26, 2025

Copy link
Copy Markdown
Contributor Author

Ok, I added another commit that adresses above concerns. getLength() should now also return correct lengths for structs with different alignments. getLength() now doesn't necessary return multiples of 4 anymore, but multiples of the biggest alignment value within the struct. (following https://webgpufundamentals.org/webgpu/lessons/webgpu-memory-layout.html#a-struct-array-size-alignment)

@Mugen87 Mugen87 added this to the r182 milestone Nov 26, 2025
@sunag sunag changed the title Fix memory length calculations for StructTypeNode (#32375) StructTypeNode: Fix memory length calculations (#32375) Nov 26, 2025
@sunag sunag merged commit 5240f29 into mrdoob:dev Nov 26, 2025
9 of 10 checks passed
@sunag

sunag commented Nov 26, 2025

Copy link
Copy Markdown
Collaborator

I think the next step is to align UniformsGroup with these changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The structNode does not calculate the correct size in memory with respect to WebGPU alignment requirements

3 participants