mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-21 07:19:30 -07:00
Implemented rudimentary support for std140 alignment of values in uniform buffers.
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
const { mat4, vec3 } = glMatrix;
|
||||||
|
|
||||||
const getCanvasSize = (canvas) => {
|
const getCanvasSize = (canvas) => {
|
||||||
const devicePixelRatio = window.devicePixelRatio ?? 1;
|
const devicePixelRatio = window.devicePixelRatio ?? 1;
|
||||||
return [canvas.clientWidth * devicePixelRatio, canvas.clientHeight * devicePixelRatio];
|
return [canvas.clientWidth * devicePixelRatio, canvas.clientHeight * devicePixelRatio];
|
||||||
@@ -29,6 +31,68 @@ const loadTexture = async (device, url) => {
|
|||||||
return texture;
|
return texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const supportedLayoutTypes = {
|
||||||
|
i32: { alignAtByte: 1, sizeInBytes: 1 },
|
||||||
|
u32: { alignAtByte: 1, sizeInBytes: 1 },
|
||||||
|
f32: { alignAtByte: 1, sizeInBytes: 1 },
|
||||||
|
atomic: { alignAtByte: 1, sizeInBytes: 1 },
|
||||||
|
vec2: { alignAtByte: 2, sizeInBytes: 2 },
|
||||||
|
vec3: { alignAtByte: 4, sizeInBytes: 3 },
|
||||||
|
vec4: { alignAtByte: 4, sizeInBytes: 4 },
|
||||||
|
mat2x2: { alignAtByte: 2, sizeInBytes: 4 },
|
||||||
|
mat3x2: { alignAtByte: 2, sizeInBytes: 6 },
|
||||||
|
mat4x2: { alignAtByte: 2, sizeInBytes: 8 },
|
||||||
|
mat2x3: { alignAtByte: 4, sizeInBytes: 8 },
|
||||||
|
mat3x3: { alignAtByte: 4, sizeInBytes: 12 },
|
||||||
|
mat4x3: { alignAtByte: 4, sizeInBytes: 16 },
|
||||||
|
mat2x4: { alignAtByte: 4, sizeInBytes: 8 },
|
||||||
|
mat3x4: { alignAtByte: 4, sizeInBytes: 12 },
|
||||||
|
mat4x4: { alignAtByte: 4, sizeInBytes: 16 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const computeStructLayout = (types) => {
|
||||||
|
const byteOffsets = [];
|
||||||
|
let sizeInBytes = 0;
|
||||||
|
for (const type of types) {
|
||||||
|
const layout = supportedLayoutTypes[type.split("<")[0]];
|
||||||
|
if (layout == null) {
|
||||||
|
throw new Error(`Unsupported type: ${type}`);
|
||||||
|
}
|
||||||
|
sizeInBytes += sizeInBytes % layout.alignAtByte;
|
||||||
|
byteOffsets.push(sizeInBytes);
|
||||||
|
sizeInBytes += layout.sizeInBytes;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
byteOffsets,
|
||||||
|
sizeInBytes,
|
||||||
|
size: sizeInBytes * Float32Array.BYTES_PER_ELEMENT,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildStruct = (layout, values) => {
|
||||||
|
const { byteOffsets, sizeInBytes } = layout;
|
||||||
|
if (values.length !== byteOffsets.length) {
|
||||||
|
throw new Error(`This struct contains ${byteOffsets.length} values, and you supplied only ${values.length}.`);
|
||||||
|
}
|
||||||
|
let buffer = [];
|
||||||
|
let count = 0;
|
||||||
|
for (let i = 0; i < values.length; i++) {
|
||||||
|
const diff = byteOffsets[i] - count;
|
||||||
|
if (diff > 0) {
|
||||||
|
buffer.push(Array(diff).fill());
|
||||||
|
}
|
||||||
|
buffer.push(values[i]);
|
||||||
|
count += values[i].length + diff;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const diff = sizeInBytes - count;
|
||||||
|
if (diff > 0) {
|
||||||
|
buffer.push(Array(diff).fill());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.flat();
|
||||||
|
};
|
||||||
|
|
||||||
export default async (canvas, config) => {
|
export default async (canvas, config) => {
|
||||||
console.log(config);
|
console.log(config);
|
||||||
|
|
||||||
@@ -66,44 +130,42 @@ 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);
|
||||||
|
|
||||||
// prettier-ignore
|
const configStructLayout = computeStructLayout(["i32", "i32"]);
|
||||||
const configBufferSize = Float32Array.BYTES_PER_ELEMENT * (1 + 1);
|
const configBufferSize = configStructLayout.size;
|
||||||
const configBuffer = device.createBuffer({
|
const configBuffer = device.createBuffer({
|
||||||
size: configBufferSize,
|
size: configBufferSize,
|
||||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, // Which of these are necessary?
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.FRAGMENT, // Which of these are necessary?
|
||||||
mappedAtCreation: true,
|
mappedAtCreation: true,
|
||||||
});
|
});
|
||||||
new Int32Array(configBuffer.getMappedRange()).set([numColumns, numRows]);
|
new Int32Array(configBuffer.getMappedRange()).set(buildStruct(configStructLayout, [numColumns, numRows]));
|
||||||
configBuffer.unmap();
|
configBuffer.unmap();
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const msdfBufferSize = Float32Array.BYTES_PER_ELEMENT * (1);
|
const msdfStructLayout = computeStructLayout(["f32"]);
|
||||||
const msdfBuffer = device.createBuffer({
|
const msdfBuffer = device.createBuffer({
|
||||||
size: msdfBufferSize,
|
size: msdfStructLayout.size,
|
||||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.FRAGMENT | GPUBufferUsage.COPY_DST, // Which of these are necessary?
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.FRAGMENT, // Which of these are necessary?
|
||||||
mappedAtCreation: true,
|
mappedAtCreation: true,
|
||||||
});
|
});
|
||||||
new Int32Array(msdfBuffer.getMappedRange()).set([config.glyphTextureColumns]);
|
new Int32Array(msdfBuffer.getMappedRange()).set(buildStruct(msdfStructLayout, [config.glyphTextureColumns]));
|
||||||
msdfBuffer.unmap();
|
msdfBuffer.unmap();
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const timeBufferSize = Float32Array.BYTES_PER_ELEMENT * (1 + 1);
|
const timeStructLayout = computeStructLayout(["i32", "i32"]);
|
||||||
const timeBuffer = device.createBuffer({
|
const timeBuffer = device.createBuffer({
|
||||||
size: timeBufferSize,
|
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 cameraBufferSize = Float32Array.BYTES_PER_ELEMENT * (2 /* ??? */ + 2 + 16 + 16);
|
const cameraStructLayout = computeStructLayout(["vec2<f32>", "mat4x4<f32>", "mat4x4<f32>"]);
|
||||||
const cameraBuffer = device.createBuffer({
|
const cameraBuffer = device.createBuffer({
|
||||||
size: cameraBufferSize,
|
size: cameraStructLayout.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?
|
||||||
});
|
});
|
||||||
|
|
||||||
const { mat4, vec3 } = glMatrix;
|
|
||||||
const camera = mat4.create();
|
const camera = mat4.create();
|
||||||
const translation = vec3.set(vec3.create(), 0, 0.5 / numRows, -1);
|
const translation = vec3.set(vec3.create(), 0, 0.5 / numRows, -1);
|
||||||
const scale = vec3.set(vec3.create(), 1, 1, 1);
|
const scale = vec3.set(vec3.create(), 1, 1, 1);
|
||||||
@@ -116,7 +178,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(cameraBuffer, 0, new Float32Array([...screenSize, /* ??? */ -1, -1, ...camera, ...transform]));
|
queue.writeBuffer(cameraBuffer, 0, new Float32Array(buildStruct(cameraStructLayout, [screenSize, camera, transform])));
|
||||||
};
|
};
|
||||||
updateCameraBuffer();
|
updateCameraBuffer();
|
||||||
|
|
||||||
@@ -220,7 +282,7 @@ export default async (canvas, config) => {
|
|||||||
updateCameraBuffer();
|
updateCameraBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.writeBuffer(timeBuffer, 0, new Int32Array([now, frame]));
|
queue.writeBuffer(timeBuffer, 0, new Int32Array(buildStruct(timeStructLayout, [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