mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-14 12:29:30 -07:00
Trying to implement the spec for the alignment and size of struct and array fields in gpu-uniforms.
This commit is contained in:
5
TODO.txt
5
TODO.txt
@@ -7,14 +7,15 @@ WebGPU
|
||||
|
||||
Try to change post processing to compute shaders once they're easier to support
|
||||
|
||||
gpu-uniforms
|
||||
gpu-uniforms, working title
|
||||
Is this an adequate name for it? Can't it be useful for non-uniform-related things?
|
||||
gpu-buffer maybe?
|
||||
Resolve the remaining to-dos
|
||||
Get all the units to be the same
|
||||
Try and use it for the palette color buffer
|
||||
Test it
|
||||
Demo it to others
|
||||
Make improvements
|
||||
Capture expected requirements down the road, make roadmap
|
||||
License it and put it somewhere else
|
||||
|
||||
|
||||
|
||||
@@ -24,18 +24,19 @@ const simpleTypes = {
|
||||
["f32"]: [1, 1, "f32", zero],
|
||||
|
||||
["atomic<i32>"]: [1, 1, "i32", zero],
|
||||
["vec2<i32>"]: [2, 2, "i32", array(2)],
|
||||
["vec3<i32>"]: [4, 3, "i32", array(3)],
|
||||
["vec4<i32>"]: [4, 4, "i32", array(4)],
|
||||
|
||||
["atomic<u32>"]: [1, 1, "u32", zero],
|
||||
["vec2<u32>"]: [2, 2, "u32", array(2)],
|
||||
["vec3<u32>"]: [4, 3, "u32", array(3)],
|
||||
["vec4<u32>"]: [4, 4, "u32", array(4)],
|
||||
|
||||
["atomic<f32>"]: [1, 1, "f32", zero],
|
||||
|
||||
["vec2<i32>"]: [2, 2, "i32", array(2)],
|
||||
["vec2<u32>"]: [2, 2, "u32", array(2)],
|
||||
["vec2<f32>"]: [2, 2, "f32", array(2)],
|
||||
|
||||
["vec3<i32>"]: [4, 3, "i32", array(3)],
|
||||
["vec3<u32>"]: [4, 3, "u32", array(3)],
|
||||
["vec3<f32>"]: [4, 3, "f32", array(3)],
|
||||
|
||||
["vec4<i32>"]: [4, 4, "i32", array(4)],
|
||||
["vec4<u32>"]: [4, 4, "u32", array(4)],
|
||||
["vec4<f32>"]: [4, 4, "f32", array(4)],
|
||||
|
||||
["mat2x2<f32>"]: [2, 4, "f32", array(2 * 2)],
|
||||
@@ -51,21 +52,33 @@ const simpleTypes = {
|
||||
|
||||
const getTypeData = (type, attributes, otherStructLayouts) => {
|
||||
if (simpleTypes[type] != null) {
|
||||
const [alignAtByte, sizeInBytes, baseType, defaultValue] = simpleTypes[type];
|
||||
let [align, size, baseType, defaultValue] = simpleTypes[type];
|
||||
if (attributes.align != null) {
|
||||
align = parseInt(attributes.align) / 4;
|
||||
}
|
||||
if (attributes.size != null) {
|
||||
size = parseInt(attributes.size) / 4;
|
||||
}
|
||||
return {
|
||||
baseType,
|
||||
alignAtByte,
|
||||
sizeInBytes,
|
||||
align,
|
||||
size,
|
||||
defaultValue,
|
||||
};
|
||||
} else if (type in otherStructLayouts) {
|
||||
const innerLayout = otherStructLayouts[type];
|
||||
const { alignAtByte, sizeInBytes } = innerLayout;
|
||||
let { align, size } = innerLayout;
|
||||
if (attributes.align != null) {
|
||||
align = parseInt(attributes.align) / 4;
|
||||
}
|
||||
if (attributes.size != null) {
|
||||
size = parseInt(attributes.size) / 4;
|
||||
}
|
||||
return {
|
||||
isStruct: true,
|
||||
innerLayout,
|
||||
sizeInBytes,
|
||||
alignAtByte,
|
||||
size,
|
||||
align,
|
||||
defaultValue: () => makeDataForLayout(otherStructLayouts, innerLayout),
|
||||
};
|
||||
} else if (type.startsWith("array<")) {
|
||||
@@ -77,16 +90,19 @@ const getTypeData = (type, attributes, otherStructLayouts) => {
|
||||
const innerTypeData = getTypeData(innerType, [], otherStructLayouts);
|
||||
|
||||
const mult = parseInt(fixedSize ?? "0");
|
||||
const alignAtByte = 1; // TODO: calculate based on align rule of arrays
|
||||
const sizeInBytes = 1; // TODO: calculate based on size rule of arrays
|
||||
// TODO: support stride attribute
|
||||
let align = innerTypeData.align;
|
||||
let size = Math.ceil(innerTypeData.size / align) * align * mult;
|
||||
if (attributes.stride != null) {
|
||||
size = parseInt(attributes.stride) * mult;
|
||||
}
|
||||
|
||||
return {
|
||||
isArray: true,
|
||||
isFixedSize: mult > 0,
|
||||
innerTypeData,
|
||||
mult,
|
||||
sizeInBytes,
|
||||
alignAtByte,
|
||||
size,
|
||||
align,
|
||||
defaultValue: () =>
|
||||
Array(mult)
|
||||
.fill()
|
||||
@@ -99,11 +115,11 @@ const getTypeData = (type, attributes, otherStructLayouts) => {
|
||||
};
|
||||
|
||||
const parseAttributes = (str) => {
|
||||
const attributes = [];
|
||||
const attributes = {};
|
||||
for (const attr of str.split(",").filter((attr) => attr.length > 0)) {
|
||||
const match = attr.match(/(\w+)(\((.*)\))?/); // foo(bar)
|
||||
const [_, name, __, value] = match;
|
||||
attributes.push({ name, value });
|
||||
attributes[name] = value;
|
||||
}
|
||||
return attributes;
|
||||
};
|
||||
@@ -126,8 +142,7 @@ const parseStruct = (str, structLayouts) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
byteOffset = Math.ceil(byteOffset / typeData.alignAtByte) * typeData.alignAtByte;
|
||||
// TODO: support align and size attributes
|
||||
byteOffset = Math.ceil(byteOffset / typeData.align) * typeData.align;
|
||||
fields.push({
|
||||
attributes: parseAttributes(leftAttributes ?? ""),
|
||||
identifier,
|
||||
@@ -135,13 +150,13 @@ const parseStruct = (str, structLayouts) => {
|
||||
...typeData,
|
||||
byteOffset,
|
||||
});
|
||||
byteOffset += typeData.sizeInBytes;
|
||||
byteOffset += typeData.size;
|
||||
}
|
||||
|
||||
const minSizeInBytes = byteOffset * BYTES_PER_ELEMENT;
|
||||
const sizeInBytes = minSizeInBytes; // TODO: support runtime-sized arrays
|
||||
const alignAtByte = 1; // TODO: calculate based on align rule of structs
|
||||
return { name, fields, sizeInBytes, alignAtByte };
|
||||
const align = Math.max(...fields.map((field) => field.align));
|
||||
const size = Math.ceil(minSizeInBytes / align) * align; // TODO: support runtime-sized arrays
|
||||
return { name, fields, size, align };
|
||||
};
|
||||
|
||||
const parseStructLayoutsFromShader = (wgsl) => {
|
||||
@@ -189,12 +204,12 @@ const writeField = (allLayouts, field, value, views, byteOffset, warnMissingFiel
|
||||
};
|
||||
|
||||
const makeGenerator = (layout, structLayouts) => {
|
||||
const minSize = layout.sizeInBytes;
|
||||
const minSize = layout.size;
|
||||
return Object.freeze({
|
||||
minSize,
|
||||
create: () => makeDataForLayout(structLayouts, layout),
|
||||
write: (object, destination, warnMissingFields = false) => {
|
||||
destination ??= new ArrayBuffer(layout.sizeInBytes); // TODO: expand to support runtime-sized arrays, via the length of the array on the data object
|
||||
destination ??= new ArrayBuffer(layout.size); // TODO: expand to support runtime-sized arrays, via the length of the array on the data object
|
||||
|
||||
const views = {
|
||||
i32: new Int32Array(destination),
|
||||
|
||||
Reference in New Issue
Block a user