Skip to content

Commit 5240f29

Browse files
authored
StructTypeNode: Fix memory length calculations (#32377)
1 parent 9a0da1a commit 5240f29

File tree

2 files changed

+16
-22
lines changed

2 files changed

+16
-22
lines changed

src/nodes/core/NodeUtils.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,22 @@ export function getMemoryLengthFromType( type ) {
181181
}
182182

183183
/**
184-
* Returns the byte boundary for the given data type.
184+
* Returns the alignment requirement for the given data type.
185185
*
186186
* @private
187187
* @method
188188
* @param {string} type - The data type.
189-
* @return {number} The byte boundary.
189+
* @return {number} The alignment requirement in bytes.
190190
*/
191-
export function getByteBoundaryFromType( type ) {
191+
export function getAlignmentFromType( type ) {
192192

193193
if ( /float|int|uint/.test( type ) ) return 4;
194194
if ( /vec2/.test( type ) ) return 8;
195195
if ( /vec3/.test( type ) ) return 16;
196196
if ( /vec4/.test( type ) ) return 16;
197197
if ( /mat2/.test( type ) ) return 8;
198-
if ( /mat3/.test( type ) ) return 48;
199-
if ( /mat4/.test( type ) ) return 64;
198+
if ( /mat3/.test( type ) ) return 16;
199+
if ( /mat4/.test( type ) ) return 16;
200200

201201
error( 'TSL: Unsupported type:', type );
202202

src/nodes/core/StructTypeNode.js

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
import Node from './Node.js';
3-
import { getByteBoundaryFromType, getMemoryLengthFromType } from './NodeUtils.js';
3+
import { getAlignmentFromType, getMemoryLengthFromType } from './NodeUtils.js';
44

55
/**
66
* Generates a layout for struct members.
@@ -86,37 +86,31 @@ class StructTypeNode extends Node {
8686
*/
8787
getLength() {
8888

89-
const GPU_CHUNK_BYTES = 8;
9089
const BYTES_PER_ELEMENT = Float32Array.BYTES_PER_ELEMENT;
91-
92-
let offset = 0; // global buffer offset in bytes
90+
let maxAlignment = 1; // maximum alignment value in this struct
91+
let offset = 0; // global buffer offset in 4 byte elements
9392

9493
for ( const member of this.membersLayout ) {
9594

9695
const type = member.type;
9796

98-
const itemSize = getMemoryLengthFromType( type ) * BYTES_PER_ELEMENT;
99-
const boundary = getByteBoundaryFromType( type );
100-
101-
const chunkOffset = offset % GPU_CHUNK_BYTES; // offset in the current chunk
102-
const chunkPadding = chunkOffset % boundary; // required padding to match boundary
103-
const chunkStart = chunkOffset + chunkPadding; // start position in the current chunk for the data
104-
105-
offset += chunkPadding;
97+
const itemSize = getMemoryLengthFromType( type );
98+
const alignment = getAlignmentFromType( type ) / BYTES_PER_ELEMENT;
99+
maxAlignment = Math.max( maxAlignment, alignment );
106100

107-
// Check for chunk overflow
108-
if ( chunkStart !== 0 && ( GPU_CHUNK_BYTES - chunkStart ) < itemSize ) {
101+
const chunkOffset = offset % maxAlignment; // offset in the current chunk of maxAlignment elements
102+
const overhang = chunkOffset % alignment; // distance from the last aligned offset
103+
if ( overhang !== 0 ) {
109104

110-
// Add padding to the end of the chunk
111-
offset += ( GPU_CHUNK_BYTES - chunkStart );
105+
offset += alignment - overhang; // move to next aligned offset
112106

113107
}
114108

115109
offset += itemSize;
116110

117111
}
118112

119-
return ( Math.ceil( offset / GPU_CHUNK_BYTES ) * GPU_CHUNK_BYTES ) / BYTES_PER_ELEMENT;
113+
return ( Math.ceil( offset / maxAlignment ) * maxAlignment ); // ensure length is a multiple of maxAlignment
120114

121115
}
122116

0 commit comments

Comments
 (0)