mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-18 14:19:30 -07:00
Renamed gpu-uniforms to gpu-buffer, and messed around with its API.
I believe all the align, size, stride and byteOffset values are now in the proper units, ie. bytes.
This commit is contained in:
22
TODO.txt
22
TODO.txt
@@ -1,24 +1,18 @@
|
|||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
|
gpu-buffer, working title
|
||||||
|
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
|
||||||
|
|
||||||
WebGPU
|
WebGPU
|
||||||
blur pass
|
blur pass
|
||||||
|
|
||||||
Update links in issues
|
Update links in issues
|
||||||
|
|
||||||
Try to change post processing to compute shaders once they're easier to support
|
Try to change post processing to compute shaders once they're easier to support
|
||||||
|
|
||||||
gpu-uniforms, working title
|
|
||||||
Is this an adequate name for it? Can't it be useful for non-uniform-related things?
|
|
||||||
gpu-buffer maybe?
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
Write an explanation of the rain pass (and include images)
|
Write an explanation of the rain pass (and include images)
|
||||||
Compute
|
Compute
|
||||||
Volumetric quads
|
Volumetric quads
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import uniforms from "/lib/gpu-uniforms.js";
|
import { loadTexture, loadShader, makeBindGroup, makePassFBO, makePass } from "./utils.js";
|
||||||
import { loadTexture, loadShader, makeUniformBuffer, makeBindGroup, makePassFBO, makePass } from "./utils.js";
|
|
||||||
|
|
||||||
// Multiplies the rendered rain and bloom by a loaded in image
|
// Multiplies the rendered rain and bloom by a loaded in image
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import uniforms from "/lib/gpu-uniforms.js";
|
import { structs } from "/lib/gpu-buffer.js";
|
||||||
import { getCanvasSize, makeUniformBuffer, makePipeline } from "./utils.js";
|
import { getCanvasSize, makeUniformBuffer, makePipeline } from "./utils.js";
|
||||||
|
|
||||||
import makeRain from "./rainPass.js";
|
import makeRain from "./rainPass.js";
|
||||||
@@ -38,7 +38,7 @@ export default async (canvas, config) => {
|
|||||||
GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_DST,
|
GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_DST,
|
||||||
};
|
};
|
||||||
|
|
||||||
const timeUniforms = uniforms.read(`[[block]] struct Time { seconds : f32; frames : i32; };`).Time;
|
const timeUniforms = structs.from(`[[block]] struct Time { seconds : f32; frames : i32; };`).Time;
|
||||||
const timeBuffer = makeUniformBuffer(device, timeUniforms);
|
const timeBuffer = makeUniformBuffer(device, timeUniforms);
|
||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
@@ -68,7 +68,7 @@ export default async (canvas, config) => {
|
|||||||
pipeline.forEach((step) => step.setSize(...canvasSize));
|
pipeline.forEach((step) => step.setSize(...canvasSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
device.queue.writeBuffer(timeBuffer, 0, timeUniforms.write({ seconds: (now - start) / 1000, frames }));
|
device.queue.writeBuffer(timeBuffer, 0, timeUniforms.toBuffer({ seconds: (now - start) / 1000, frames }));
|
||||||
frames++;
|
frames++;
|
||||||
|
|
||||||
const encoder = device.createCommandEncoder();
|
const encoder = device.createCommandEncoder();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import uniforms from "/lib/gpu-uniforms.js";
|
import { structs } from "/lib/gpu-buffer.js";
|
||||||
import { loadShader, makeUniformBuffer, makeBindGroup, makePassFBO, makePass } from "./utils.js";
|
import { loadShader, makeUniformBuffer, makeBindGroup, makePassFBO, makePass } from "./utils.js";
|
||||||
|
|
||||||
// Maps the brightness of the rendered rain and bloom to colors
|
// Maps the brightness of the rendered rain and bloom to colors
|
||||||
@@ -123,7 +123,7 @@ export default (context, getInputs) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const paletteShaderUniforms = uniforms.read(paletteShader.code);
|
const paletteShaderUniforms = structs.from(paletteShader.code);
|
||||||
const configUniforms = paletteShaderUniforms.Config;
|
const configUniforms = paletteShaderUniforms.Config;
|
||||||
configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor });
|
configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor });
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import uniforms from "/lib/gpu-uniforms.js";
|
import { structs, byteSizeOf } from "/lib/gpu-buffer.js";
|
||||||
import { makePassFBO, loadTexture, loadShader, makeUniformBuffer, makeBindGroup, makePass } from "./utils.js";
|
import { makePassFBO, loadTexture, loadShader, makeUniformBuffer, makeBindGroup, makePass } from "./utils.js";
|
||||||
|
|
||||||
const { mat4, vec3 } = glMatrix;
|
const { mat4, vec3 } = glMatrix;
|
||||||
@@ -47,7 +47,7 @@ export default (context, getInputs) => {
|
|||||||
const numQuads = config.volumetric ? numCells : 1;
|
const numQuads = config.volumetric ? numCells : 1;
|
||||||
|
|
||||||
const cellsBuffer = device.createBuffer({
|
const cellsBuffer = device.createBuffer({
|
||||||
size: numCells * uniforms.byteSizeOf("vec4<f32>"),
|
size: numCells * byteSizeOf("vec4<f32>"),
|
||||||
usage: GPUBufferUsage.STORAGE,
|
usage: GPUBufferUsage.STORAGE,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ export default (context, getInputs) => {
|
|||||||
const ready = (async () => {
|
const ready = (async () => {
|
||||||
const [msdfTexture, rainShader] = await Promise.all(assets);
|
const [msdfTexture, rainShader] = await Promise.all(assets);
|
||||||
|
|
||||||
const rainShaderUniforms = uniforms.read(rainShader.code);
|
const rainShaderUniforms = structs.from(rainShader.code);
|
||||||
configBuffer = makeConfigBuffer(device, rainShaderUniforms.Config, config, density, gridSize);
|
configBuffer = makeConfigBuffer(device, rainShaderUniforms.Config, config, density, gridSize);
|
||||||
|
|
||||||
sceneUniforms = rainShaderUniforms.Scene;
|
sceneUniforms = rainShaderUniforms.Scene;
|
||||||
@@ -147,7 +147,7 @@ export default (context, getInputs) => {
|
|||||||
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];
|
||||||
device.queue.writeBuffer(sceneBuffer, 0, sceneUniforms.write({ screenSize, camera, transform }));
|
device.queue.writeBuffer(sceneBuffer, 0, sceneUniforms.toBuffer({ screenSize, camera, transform }));
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
output?.destroy();
|
output?.destroy();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import uniforms from "/lib/gpu-uniforms.js";
|
import { structs } from "/lib/gpu-buffer.js";
|
||||||
import { loadShader, makeUniformBuffer, makePassFBO, makePass } from "./utils.js";
|
import { loadShader, makeUniformBuffer, makePassFBO, makePass } from "./utils.js";
|
||||||
|
|
||||||
// Matrix Resurrections isn't in theaters yet,
|
// Matrix Resurrections isn't in theaters yet,
|
||||||
@@ -56,7 +56,7 @@ export default (context, getInputs) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const configUniforms = uniforms.read(resurrectionShader.code).Config;
|
const configUniforms = structs.from(resurrectionShader.code).Config;
|
||||||
configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor });
|
configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor });
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import uniforms from "/lib/gpu-uniforms.js";
|
import { structs } from "/lib/gpu-buffer.js";
|
||||||
import { loadShader, make1DTexture, makeUniformBuffer, makeBindGroup, makePassFBO, makePass } from "./utils.js";
|
import { loadShader, make1DTexture, makeUniformBuffer, makeBindGroup, makePassFBO, makePass } from "./utils.js";
|
||||||
|
|
||||||
// Multiplies the rendered rain and bloom by a 1D gradient texture
|
// Multiplies the rendered rain and bloom by a 1D gradient texture
|
||||||
@@ -91,7 +91,7 @@ export default (context, getInputs) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const configUniforms = uniforms.read(stripeShader.code).Config;
|
const configUniforms = structs.from(stripeShader.code).Config;
|
||||||
configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor });
|
configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor });
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ const makeUniformBuffer = (device, uniforms, data = null) => {
|
|||||||
mappedAtCreation: data != null,
|
mappedAtCreation: data != null,
|
||||||
});
|
});
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
uniforms.write(data, buffer.getMappedRange());
|
uniforms.toBuffer(data, buffer.getMappedRange());
|
||||||
buffer.unmap();
|
buffer.unmap();
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|||||||
@@ -12,50 +12,49 @@
|
|||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
|
|
||||||
const BYTES_PER_ELEMENT = 4;
|
|
||||||
const zero = () => 0;
|
const zero = () => 0;
|
||||||
const array = (n) => () => Array(n).fill(0);
|
const array = (n) => () => Array(n).fill(0);
|
||||||
|
|
||||||
const simpleTypes = {
|
const simpleTypes = {
|
||||||
["i32"]: [1, 1, "i32", zero],
|
["i32"]: [4, 4, "i32", zero],
|
||||||
["u32"]: [1, 1, "u32", zero],
|
["u32"]: [4, 4, "u32", zero],
|
||||||
["f32"]: [1, 1, "f32", zero],
|
["f32"]: [4, 4, "f32", zero],
|
||||||
|
|
||||||
["atomic<i32>"]: [1, 1, "i32", zero],
|
["atomic<i32>"]: [4, 4, "i32", zero],
|
||||||
["atomic<u32>"]: [1, 1, "u32", zero],
|
["atomic<u32>"]: [4, 4, "u32", zero],
|
||||||
["atomic<f32>"]: [1, 1, "f32", zero],
|
["atomic<f32>"]: [4, 4, "f32", zero],
|
||||||
|
|
||||||
["vec2<i32>"]: [2, 2, "i32", array(2)],
|
["vec2<i32>"]: [8, 8, "i32", array(2)],
|
||||||
["vec2<u32>"]: [2, 2, "u32", array(2)],
|
["vec2<u32>"]: [8, 8, "u32", array(2)],
|
||||||
["vec2<f32>"]: [2, 2, "f32", array(2)],
|
["vec2<f32>"]: [8, 8, "f32", array(2)],
|
||||||
|
|
||||||
["vec3<i32>"]: [4, 3, "i32", array(3)],
|
["vec3<i32>"]: [16, 12, "i32", array(3)],
|
||||||
["vec3<u32>"]: [4, 3, "u32", array(3)],
|
["vec3<u32>"]: [16, 12, "u32", array(3)],
|
||||||
["vec3<f32>"]: [4, 3, "f32", array(3)],
|
["vec3<f32>"]: [16, 12, "f32", array(3)],
|
||||||
|
|
||||||
["vec4<i32>"]: [4, 4, "i32", array(4)],
|
["vec4<i32>"]: [16, 16, "i32", array(4)],
|
||||||
["vec4<u32>"]: [4, 4, "u32", array(4)],
|
["vec4<u32>"]: [16, 16, "u32", array(4)],
|
||||||
["vec4<f32>"]: [4, 4, "f32", array(4)],
|
["vec4<f32>"]: [16, 16, "f32", array(4)],
|
||||||
|
|
||||||
["mat2x2<f32>"]: [2, 4, "f32", array(2 * 2)],
|
["mat2x2<f32>"]: [8, 16, "f32", array(2 * 2)],
|
||||||
["mat3x2<f32>"]: [2, 6, "f32", array(3 * 2)],
|
["mat3x2<f32>"]: [8, 24, "f32", array(3 * 2)],
|
||||||
["mat4x2<f32>"]: [2, 8, "f32", array(4 * 2)],
|
["mat4x2<f32>"]: [8, 32, "f32", array(4 * 2)],
|
||||||
["mat2x3<f32>"]: [4, 8, "f32", array(2 * 3)],
|
["mat2x3<f32>"]: [16, 32, "f32", array(2 * 3)],
|
||||||
["mat3x3<f32>"]: [4, 12, "f32", array(3 * 3)],
|
["mat3x3<f32>"]: [16, 48, "f32", array(3 * 3)],
|
||||||
["mat4x3<f32>"]: [4, 16, "f32", array(4 * 3)],
|
["mat4x3<f32>"]: [16, 64, "f32", array(4 * 3)],
|
||||||
["mat2x4<f32>"]: [4, 8, "f32", array(2 * 4)],
|
["mat2x4<f32>"]: [16, 32, "f32", array(2 * 4)],
|
||||||
["mat3x4<f32>"]: [4, 12, "f32", array(3 * 4)],
|
["mat3x4<f32>"]: [16, 48, "f32", array(3 * 4)],
|
||||||
["mat4x4<f32>"]: [4, 16, "f32", array(4 * 4)],
|
["mat4x4<f32>"]: [16, 64, "f32", array(4 * 4)],
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTypeData = (type, attributes, otherStructLayouts) => {
|
const getTypeData = (type, attributes, otherStructLayouts) => {
|
||||||
if (simpleTypes[type] != null) {
|
if (simpleTypes[type] != null) {
|
||||||
let [align, size, baseType, defaultValue] = simpleTypes[type];
|
let [align, size, baseType, defaultValue] = simpleTypes[type];
|
||||||
if (attributes.align != null) {
|
if (attributes.align != null) {
|
||||||
align = parseInt(attributes.align) / 4;
|
align = parseInt(attributes.align);
|
||||||
}
|
}
|
||||||
if (attributes.size != null) {
|
if (attributes.size != null) {
|
||||||
size = parseInt(attributes.size) / 4;
|
size = parseInt(attributes.size);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
baseType,
|
baseType,
|
||||||
@@ -67,10 +66,10 @@ const getTypeData = (type, attributes, otherStructLayouts) => {
|
|||||||
const innerLayout = otherStructLayouts[type];
|
const innerLayout = otherStructLayouts[type];
|
||||||
let { align, size } = innerLayout;
|
let { align, size } = innerLayout;
|
||||||
if (attributes.align != null) {
|
if (attributes.align != null) {
|
||||||
align = parseInt(attributes.align) / 4;
|
align = parseInt(attributes.align);
|
||||||
}
|
}
|
||||||
if (attributes.size != null) {
|
if (attributes.size != null) {
|
||||||
size = parseInt(attributes.size) / 4;
|
size = parseInt(attributes.size);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
isStruct: true,
|
isStruct: true,
|
||||||
@@ -153,7 +152,7 @@ const parseStruct = (str, structLayouts) => {
|
|||||||
byteOffset += typeData.size;
|
byteOffset += typeData.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const minSizeInBytes = byteOffset * BYTES_PER_ELEMENT;
|
const minSizeInBytes = byteOffset;
|
||||||
const align = Math.max(...fields.map((field) => field.align));
|
const align = Math.max(...fields.map((field) => field.align));
|
||||||
const size = Math.ceil(minSizeInBytes / align) * align;
|
const size = Math.ceil(minSizeInBytes / align) * align;
|
||||||
return { name, fields, size, align };
|
return { name, fields, size, align };
|
||||||
@@ -199,7 +198,7 @@ const writeField = (allLayouts, field, value, views, byteOffset, warnMissingFiel
|
|||||||
} else {
|
} else {
|
||||||
const view = views[field.baseType];
|
const view = views[field.baseType];
|
||||||
const array = value[Symbol.iterator] == null ? [Number(value)] : value;
|
const array = value[Symbol.iterator] == null ? [Number(value)] : value;
|
||||||
view.set(array, byteOffset + field.byteOffset);
|
view.set(array, (byteOffset + field.byteOffset) / 4);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -208,7 +207,7 @@ const makeGenerator = (layout, structLayouts) => {
|
|||||||
return Object.freeze({
|
return Object.freeze({
|
||||||
minSize,
|
minSize,
|
||||||
create: () => makeDataForLayout(structLayouts, layout),
|
create: () => makeDataForLayout(structLayouts, layout),
|
||||||
write: (object, destination, warnMissingFields = false) => {
|
toBuffer: (object, destination, warnMissingFields = false) => {
|
||||||
if (destination == null) {
|
if (destination == null) {
|
||||||
let size = layout.size;
|
let size = layout.size;
|
||||||
const lastField = layout.fields[layout.fields.length - 1];
|
const lastField = layout.fields[layout.fields.length - 1];
|
||||||
@@ -233,15 +232,16 @@ const makeGenerator = (layout, structLayouts) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const api = Object.freeze({
|
const byteSizeOf = (simpleType) => simpleTypes[simpleType]?.[1];
|
||||||
read: (wgsl) => {
|
|
||||||
|
const structs = Object.freeze({
|
||||||
|
from: (wgsl) => {
|
||||||
if (typeof wgsl !== "string") {
|
if (typeof wgsl !== "string") {
|
||||||
throw new Error("Input is not a string.");
|
throw new Error("Input is not a string.");
|
||||||
}
|
}
|
||||||
const structLayouts = parseStructLayoutsFromShader(wgsl);
|
const structLayouts = parseStructLayoutsFromShader(wgsl);
|
||||||
return Object.fromEntries(Object.entries(structLayouts).map(([name, layout]) => [name, makeGenerator(layout, structLayouts)]));
|
return Object.fromEntries(Object.entries(structLayouts).map(([name, layout]) => [name, makeGenerator(layout, structLayouts)]));
|
||||||
},
|
},
|
||||||
byteSizeOf: (simpleType) => simpleTypes[simpleType][1] * BYTES_PER_ELEMENT,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default api;
|
export { structs, byteSizeOf };
|
||||||
Reference in New Issue
Block a user