mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-21 07:19:30 -07:00
Moving std140 code to its own module. Here it can evolve into a class or whatever, and it won't clutter the rest of the code.
This commit is contained in:
77
js/std140.js
Normal file
77
js/std140.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
const supportedLayoutTypes = {
|
||||||
|
["i32"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "i32" },
|
||||||
|
["u32"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "u32" },
|
||||||
|
["f32"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "f32" },
|
||||||
|
|
||||||
|
["atomic<i32>"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "i32" },
|
||||||
|
["vec2<i32>"]: { alignAtByte: 2, sizeInBytes: 2, baseType: "i32" },
|
||||||
|
["vec3<i32>"]: { alignAtByte: 4, sizeInBytes: 3, baseType: "i32" },
|
||||||
|
["vec4<i32>"]: { alignAtByte: 4, sizeInBytes: 4, baseType: "i32" },
|
||||||
|
|
||||||
|
["atomic<u32>"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "u32" },
|
||||||
|
["vec2<u32>"]: { alignAtByte: 2, sizeInBytes: 2, baseType: "u32" },
|
||||||
|
["vec3<u32>"]: { alignAtByte: 4, sizeInBytes: 3, baseType: "u32" },
|
||||||
|
["vec4<u32>"]: { alignAtByte: 4, sizeInBytes: 4, baseType: "u32" },
|
||||||
|
|
||||||
|
["atomic<f32>"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "f32" },
|
||||||
|
["vec2<f32>"]: { alignAtByte: 2, sizeInBytes: 2, baseType: "f32" },
|
||||||
|
["vec3<f32>"]: { alignAtByte: 4, sizeInBytes: 3, baseType: "f32" },
|
||||||
|
["vec4<f32>"]: { alignAtByte: 4, sizeInBytes: 4, baseType: "f32" },
|
||||||
|
|
||||||
|
["mat2x2<f32>"]: { alignAtByte: 2, sizeInBytes: 4, baseType: "f32" },
|
||||||
|
["mat3x2<f32>"]: { alignAtByte: 2, sizeInBytes: 6, baseType: "f32" },
|
||||||
|
["mat4x2<f32>"]: { alignAtByte: 2, sizeInBytes: 8, baseType: "f32" },
|
||||||
|
["mat2x3<f32>"]: { alignAtByte: 4, sizeInBytes: 8, baseType: "f32" },
|
||||||
|
["mat3x3<f32>"]: { alignAtByte: 4, sizeInBytes: 12, baseType: "f32" },
|
||||||
|
["mat4x3<f32>"]: { alignAtByte: 4, sizeInBytes: 16, baseType: "f32" },
|
||||||
|
["mat2x4<f32>"]: { alignAtByte: 4, sizeInBytes: 8, baseType: "f32" },
|
||||||
|
["mat3x4<f32>"]: { alignAtByte: 4, sizeInBytes: 12, baseType: "f32" },
|
||||||
|
["mat4x4<f32>"]: { alignAtByte: 4, sizeInBytes: 16, baseType: "f32" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const computeStructLayout = (types) => {
|
||||||
|
const entries = [];
|
||||||
|
let byteOffset = 0;
|
||||||
|
for (const type of types) {
|
||||||
|
if (supportedLayoutTypes[type] == null) {
|
||||||
|
throw new Error(`Unsupported type: ${type}`);
|
||||||
|
}
|
||||||
|
const { alignAtByte, sizeInBytes, baseType } = supportedLayoutTypes[type];
|
||||||
|
byteOffset = Math.ceil(byteOffset / alignAtByte) * alignAtByte;
|
||||||
|
entries.push({ baseType, byteOffset });
|
||||||
|
byteOffset += sizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(types);
|
||||||
|
// console.log(entries);
|
||||||
|
|
||||||
|
const size = byteOffset * Float32Array.BYTES_PER_ELEMENT;
|
||||||
|
|
||||||
|
return {
|
||||||
|
entries,
|
||||||
|
size,
|
||||||
|
build: (values, buffer = null) => buildStruct(entries, values, buffer ?? new ArrayBuffer(size)),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildStruct = (entries, values, buffer) => {
|
||||||
|
if (values.length !== entries.length) {
|
||||||
|
throw new Error(`This struct contains ${entries.length} values, and you supplied ${values.length}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const views = {
|
||||||
|
i32: new Int32Array(buffer),
|
||||||
|
u32: new Uint32Array(buffer),
|
||||||
|
f32: new Float32Array(buffer),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < values.length; i++) {
|
||||||
|
const view = views[entries[i].baseType];
|
||||||
|
const value = values[i];
|
||||||
|
const array = value[Symbol.iterator] == null ? [value] : value;
|
||||||
|
view.set(array, entries[i].byteOffset);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default computeStructLayout;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import std140 from "./std140.js";
|
||||||
const { mat4, vec3 } = glMatrix;
|
const { mat4, vec3 } = glMatrix;
|
||||||
|
|
||||||
const getCanvasSize = (canvas) => {
|
const getCanvasSize = (canvas) => {
|
||||||
@@ -31,83 +32,6 @@ const loadTexture = async (device, url) => {
|
|||||||
return texture;
|
return texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
const supportedLayoutTypes = {
|
|
||||||
["i32"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "i32" },
|
|
||||||
["u32"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "u32" },
|
|
||||||
["f32"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "f32" },
|
|
||||||
|
|
||||||
["atomic<i32>"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "i32" },
|
|
||||||
["vec2<i32>"]: { alignAtByte: 2, sizeInBytes: 2, baseType: "i32" },
|
|
||||||
["vec3<i32>"]: { alignAtByte: 4, sizeInBytes: 3, baseType: "i32" },
|
|
||||||
["vec4<i32>"]: { alignAtByte: 4, sizeInBytes: 4, baseType: "i32" },
|
|
||||||
|
|
||||||
["atomic<u32>"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "u32" },
|
|
||||||
["vec2<u32>"]: { alignAtByte: 2, sizeInBytes: 2, baseType: "u32" },
|
|
||||||
["vec3<u32>"]: { alignAtByte: 4, sizeInBytes: 3, baseType: "u32" },
|
|
||||||
["vec4<u32>"]: { alignAtByte: 4, sizeInBytes: 4, baseType: "u32" },
|
|
||||||
|
|
||||||
["atomic<f32>"]: { alignAtByte: 1, sizeInBytes: 1, baseType: "f32" },
|
|
||||||
["vec2<f32>"]: { alignAtByte: 2, sizeInBytes: 2, baseType: "f32" },
|
|
||||||
["vec3<f32>"]: { alignAtByte: 4, sizeInBytes: 3, baseType: "f32" },
|
|
||||||
["vec4<f32>"]: { alignAtByte: 4, sizeInBytes: 4, baseType: "f32" },
|
|
||||||
|
|
||||||
["mat2x2<f32>"]: { alignAtByte: 2, sizeInBytes: 4, baseType: "f32" },
|
|
||||||
["mat3x2<f32>"]: { alignAtByte: 2, sizeInBytes: 6, baseType: "f32" },
|
|
||||||
["mat4x2<f32>"]: { alignAtByte: 2, sizeInBytes: 8, baseType: "f32" },
|
|
||||||
["mat2x3<f32>"]: { alignAtByte: 4, sizeInBytes: 8, baseType: "f32" },
|
|
||||||
["mat3x3<f32>"]: { alignAtByte: 4, sizeInBytes: 12, baseType: "f32" },
|
|
||||||
["mat4x3<f32>"]: { alignAtByte: 4, sizeInBytes: 16, baseType: "f32" },
|
|
||||||
["mat2x4<f32>"]: { alignAtByte: 4, sizeInBytes: 8, baseType: "f32" },
|
|
||||||
["mat3x4<f32>"]: { alignAtByte: 4, sizeInBytes: 12, baseType: "f32" },
|
|
||||||
["mat4x4<f32>"]: { alignAtByte: 4, sizeInBytes: 16, baseType: "f32" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const computeStructLayout = (types) => {
|
|
||||||
const entries = [];
|
|
||||||
let byteOffset = 0;
|
|
||||||
for (const type of types) {
|
|
||||||
if (supportedLayoutTypes[type] == null) {
|
|
||||||
throw new Error(`Unsupported type: ${type}`);
|
|
||||||
}
|
|
||||||
const { alignAtByte, sizeInBytes, baseType } = supportedLayoutTypes[type];
|
|
||||||
byteOffset = Math.ceil(byteOffset / alignAtByte) * alignAtByte;
|
|
||||||
entries.push({ baseType, byteOffset });
|
|
||||||
byteOffset += sizeInBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log(types);
|
|
||||||
// console.log(entries);
|
|
||||||
|
|
||||||
return {
|
|
||||||
entries,
|
|
||||||
size: byteOffset * Float32Array.BYTES_PER_ELEMENT,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const buildStruct = (buffer, layout, values) => {
|
|
||||||
const { entries } = layout;
|
|
||||||
|
|
||||||
if (values.length !== entries.length) {
|
|
||||||
throw new Error(`This struct contains ${entries.length} values, and you supplied ${values.length}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer ??= new ArrayBuffer(layout.size);
|
|
||||||
|
|
||||||
const views = {
|
|
||||||
i32: new Int32Array(buffer),
|
|
||||||
u32: new Uint32Array(buffer),
|
|
||||||
f32: new Float32Array(buffer),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let i = 0; i < values.length; i++) {
|
|
||||||
const view = views[entries[i].baseType];
|
|
||||||
const value = values[i];
|
|
||||||
const array = value[Symbol.iterator] == null ? [value] : value;
|
|
||||||
view.set(array, entries[i].byteOffset);
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async (canvas, config) => {
|
export default async (canvas, config) => {
|
||||||
console.log(config);
|
console.log(config);
|
||||||
|
|
||||||
@@ -147,35 +71,35 @@ export default async (canvas, config) => {
|
|||||||
const sampler = device.createSampler();
|
const sampler = device.createSampler();
|
||||||
const msdfTexture = await loadTexture(device, config.glyphTexURL);
|
const msdfTexture = await loadTexture(device, config.glyphTexURL);
|
||||||
|
|
||||||
const configStructLayout = computeStructLayout(["i32", "i32", "f32"]);
|
const configStructLayout = std140(["i32", "i32", "f32"]);
|
||||||
const configBufferSize = configStructLayout.size;
|
const configBufferSize = configStructLayout.size;
|
||||||
const configBuffer = device.createBuffer({
|
const configBuffer = device.createBuffer({
|
||||||
size: configBufferSize,
|
size: configBufferSize,
|
||||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.FRAGMENT, // Which of these are necessary?
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.FRAGMENT, // Which of these are necessary?
|
||||||
mappedAtCreation: true,
|
mappedAtCreation: true,
|
||||||
});
|
});
|
||||||
buildStruct(configBuffer.getMappedRange(), configStructLayout, [numColumns, numRows, config.glyphHeightToWidth]);
|
configStructLayout.build([numColumns, numRows, config.glyphHeightToWidth], configBuffer.getMappedRange());
|
||||||
configBuffer.unmap();
|
configBuffer.unmap();
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const msdfStructLayout = computeStructLayout(["i32", "i32"]);
|
const msdfStructLayout = std140(["i32", "i32"]);
|
||||||
const msdfBuffer = device.createBuffer({
|
const msdfBuffer = device.createBuffer({
|
||||||
size: msdfStructLayout.size,
|
size: msdfStructLayout.size,
|
||||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.FRAGMENT, // Which of these are necessary?
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.FRAGMENT, // Which of these are necessary?
|
||||||
mappedAtCreation: true,
|
mappedAtCreation: true,
|
||||||
});
|
});
|
||||||
buildStruct(msdfBuffer.getMappedRange(), msdfStructLayout, [config.glyphTextureColumns, config.glyphSequenceLength]);
|
msdfStructLayout.build([config.glyphTextureColumns, config.glyphSequenceLength], msdfBuffer.getMappedRange());
|
||||||
msdfBuffer.unmap();
|
msdfBuffer.unmap();
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const timeStructLayout = computeStructLayout(["i32", "i32"]);
|
const timeStructLayout = std140(["i32", "i32"]);
|
||||||
const timeBuffer = device.createBuffer({
|
const timeBuffer = device.createBuffer({
|
||||||
size: timeStructLayout.size,
|
size: timeStructLayout.size,
|
||||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.FRAGMENT | GPUBufferUsage.COMPUTE | GPUBufferUsage.COPY_DST, // Which of these are necessary?
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.FRAGMENT | GPUBufferUsage.COMPUTE | GPUBufferUsage.COPY_DST, // Which of these are necessary?
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const sceneStructLayout = computeStructLayout(["vec2<f32>", "mat4x4<f32>", "mat4x4<f32>"]);
|
const sceneStructLayout = std140(["vec2<f32>", "mat4x4<f32>", "mat4x4<f32>"]);
|
||||||
const sceneBuffer = device.createBuffer({
|
const sceneBuffer = device.createBuffer({
|
||||||
size: sceneStructLayout.size,
|
size: sceneStructLayout.size,
|
||||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.COMPUTE | GPUBufferUsage.COPY_DST, // Which of these are necessary?
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.COMPUTE | GPUBufferUsage.COPY_DST, // Which of these are necessary?
|
||||||
@@ -193,7 +117,7 @@ export default async (canvas, config) => {
|
|||||||
const aspectRatio = canvasSize[0] / canvasSize[1];
|
const aspectRatio = canvasSize[0] / canvasSize[1];
|
||||||
mat4.perspectiveZO(camera, (Math.PI / 180) * 90, aspectRatio, 0.0001, 1000);
|
mat4.perspectiveZO(camera, (Math.PI / 180) * 90, aspectRatio, 0.0001, 1000);
|
||||||
const screenSize = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
const screenSize = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
||||||
queue.writeBuffer(sceneBuffer, 0, buildStruct(null, sceneStructLayout, [screenSize, camera, transform]));
|
queue.writeBuffer(sceneBuffer, 0, sceneStructLayout.build([screenSize, camera, transform]));
|
||||||
};
|
};
|
||||||
updateCameraBuffer();
|
updateCameraBuffer();
|
||||||
|
|
||||||
@@ -297,7 +221,7 @@ export default async (canvas, config) => {
|
|||||||
updateCameraBuffer();
|
updateCameraBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.writeBuffer(timeBuffer, 0, buildStruct(null, timeStructLayout, [now, frame]));
|
queue.writeBuffer(timeBuffer, 0, timeStructLayout.build([now, frame]));
|
||||||
frame++;
|
frame++;
|
||||||
|
|
||||||
renderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView();
|
renderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView();
|
||||||
|
|||||||
Reference in New Issue
Block a user