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:
Rezmason
2021-11-08 22:56:00 -08:00
parent cf02073ff3
commit a143e3fc03
9 changed files with 59 additions and 66 deletions

View File

@@ -1,24 +1,18 @@
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
blur pass
Update links in issues
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)
Compute
Volumetric quads

View File

@@ -1,5 +1,4 @@
import uniforms from "/lib/gpu-uniforms.js";
import { loadTexture, loadShader, makeUniformBuffer, makeBindGroup, makePassFBO, makePass } from "./utils.js";
import { loadTexture, loadShader, makeBindGroup, makePassFBO, makePass } from "./utils.js";
// Multiplies the rendered rain and bloom by a loaded in image

View File

@@ -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 makeRain from "./rainPass.js";
@@ -38,7 +38,7 @@ export default async (canvas, config) => {
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 context = {
@@ -68,7 +68,7 @@ export default async (canvas, config) => {
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++;
const encoder = device.createCommandEncoder();

View File

@@ -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";
// 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;
configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor });

View File

@@ -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";
const { mat4, vec3 } = glMatrix;
@@ -47,7 +47,7 @@ export default (context, getInputs) => {
const numQuads = config.volumetric ? numCells : 1;
const cellsBuffer = device.createBuffer({
size: numCells * uniforms.byteSizeOf("vec4<f32>"),
size: numCells * byteSizeOf("vec4<f32>"),
usage: GPUBufferUsage.STORAGE,
});
@@ -91,7 +91,7 @@ export default (context, getInputs) => {
const ready = (async () => {
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);
sceneUniforms = rainShaderUniforms.Scene;
@@ -147,7 +147,7 @@ export default (context, getInputs) => {
mat4.perspectiveZO(camera, (Math.PI / 180) * 90, aspectRatio, 0.0001, 1000);
}
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
output?.destroy();

View File

@@ -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";
// 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 });
})();

View File

@@ -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";
// 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 });
})();

View File

@@ -50,7 +50,7 @@ const makeUniformBuffer = (device, uniforms, data = null) => {
mappedAtCreation: data != null,
});
if (data != null) {
uniforms.write(data, buffer.getMappedRange());
uniforms.toBuffer(data, buffer.getMappedRange());
buffer.unmap();
}
return buffer;

View File

@@ -12,50 +12,49 @@
*
**/
const BYTES_PER_ELEMENT = 4;
const zero = () => 0;
const array = (n) => () => Array(n).fill(0);
const simpleTypes = {
["i32"]: [1, 1, "i32", zero],
["u32"]: [1, 1, "u32", zero],
["f32"]: [1, 1, "f32", zero],
["i32"]: [4, 4, "i32", zero],
["u32"]: [4, 4, "u32", zero],
["f32"]: [4, 4, "f32", zero],
["atomic<i32>"]: [1, 1, "i32", zero],
["atomic<u32>"]: [1, 1, "u32", zero],
["atomic<f32>"]: [1, 1, "f32", zero],
["atomic<i32>"]: [4, 4, "i32", zero],
["atomic<u32>"]: [4, 4, "u32", zero],
["atomic<f32>"]: [4, 4, "f32", zero],
["vec2<i32>"]: [2, 2, "i32", array(2)],
["vec2<u32>"]: [2, 2, "u32", array(2)],
["vec2<f32>"]: [2, 2, "f32", array(2)],
["vec2<i32>"]: [8, 8, "i32", array(2)],
["vec2<u32>"]: [8, 8, "u32", array(2)],
["vec2<f32>"]: [8, 8, "f32", array(2)],
["vec3<i32>"]: [4, 3, "i32", array(3)],
["vec3<u32>"]: [4, 3, "u32", array(3)],
["vec3<f32>"]: [4, 3, "f32", array(3)],
["vec3<i32>"]: [16, 12, "i32", array(3)],
["vec3<u32>"]: [16, 12, "u32", array(3)],
["vec3<f32>"]: [16, 12, "f32", array(3)],
["vec4<i32>"]: [4, 4, "i32", array(4)],
["vec4<u32>"]: [4, 4, "u32", array(4)],
["vec4<f32>"]: [4, 4, "f32", array(4)],
["vec4<i32>"]: [16, 16, "i32", array(4)],
["vec4<u32>"]: [16, 16, "u32", array(4)],
["vec4<f32>"]: [16, 16, "f32", array(4)],
["mat2x2<f32>"]: [2, 4, "f32", array(2 * 2)],
["mat3x2<f32>"]: [2, 6, "f32", array(3 * 2)],
["mat4x2<f32>"]: [2, 8, "f32", array(4 * 2)],
["mat2x3<f32>"]: [4, 8, "f32", array(2 * 3)],
["mat3x3<f32>"]: [4, 12, "f32", array(3 * 3)],
["mat4x3<f32>"]: [4, 16, "f32", array(4 * 3)],
["mat2x4<f32>"]: [4, 8, "f32", array(2 * 4)],
["mat3x4<f32>"]: [4, 12, "f32", array(3 * 4)],
["mat4x4<f32>"]: [4, 16, "f32", array(4 * 4)],
["mat2x2<f32>"]: [8, 16, "f32", array(2 * 2)],
["mat3x2<f32>"]: [8, 24, "f32", array(3 * 2)],
["mat4x2<f32>"]: [8, 32, "f32", array(4 * 2)],
["mat2x3<f32>"]: [16, 32, "f32", array(2 * 3)],
["mat3x3<f32>"]: [16, 48, "f32", array(3 * 3)],
["mat4x3<f32>"]: [16, 64, "f32", array(4 * 3)],
["mat2x4<f32>"]: [16, 32, "f32", array(2 * 4)],
["mat3x4<f32>"]: [16, 48, "f32", array(3 * 4)],
["mat4x4<f32>"]: [16, 64, "f32", array(4 * 4)],
};
const getTypeData = (type, attributes, otherStructLayouts) => {
if (simpleTypes[type] != null) {
let [align, size, baseType, defaultValue] = simpleTypes[type];
if (attributes.align != null) {
align = parseInt(attributes.align) / 4;
align = parseInt(attributes.align);
}
if (attributes.size != null) {
size = parseInt(attributes.size) / 4;
size = parseInt(attributes.size);
}
return {
baseType,
@@ -67,10 +66,10 @@ const getTypeData = (type, attributes, otherStructLayouts) => {
const innerLayout = otherStructLayouts[type];
let { align, size } = innerLayout;
if (attributes.align != null) {
align = parseInt(attributes.align) / 4;
align = parseInt(attributes.align);
}
if (attributes.size != null) {
size = parseInt(attributes.size) / 4;
size = parseInt(attributes.size);
}
return {
isStruct: true,
@@ -153,7 +152,7 @@ const parseStruct = (str, structLayouts) => {
byteOffset += typeData.size;
}
const minSizeInBytes = byteOffset * BYTES_PER_ELEMENT;
const minSizeInBytes = byteOffset;
const align = Math.max(...fields.map((field) => field.align));
const size = Math.ceil(minSizeInBytes / align) * align;
return { name, fields, size, align };
@@ -199,7 +198,7 @@ const writeField = (allLayouts, field, value, views, byteOffset, warnMissingFiel
} else {
const view = views[field.baseType];
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({
minSize,
create: () => makeDataForLayout(structLayouts, layout),
write: (object, destination, warnMissingFields = false) => {
toBuffer: (object, destination, warnMissingFields = false) => {
if (destination == null) {
let size = layout.size;
const lastField = layout.fields[layout.fields.length - 1];
@@ -233,15 +232,16 @@ const makeGenerator = (layout, structLayouts) => {
});
};
const api = Object.freeze({
read: (wgsl) => {
const byteSizeOf = (simpleType) => simpleTypes[simpleType]?.[1];
const structs = Object.freeze({
from: (wgsl) => {
if (typeof wgsl !== "string") {
throw new Error("Input is not a string.");
}
const structLayouts = parseStructLayoutsFromShader(wgsl);
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 };