The delimiter between WGSL struct fields is now a comma, which is also the delimiter between parameters in angle brackets, so gpu-buffer needs to be a little cleverer with the lines it separates.

This commit is contained in:
Rezmason
2022-04-30 18:00:35 -07:00
parent e8458a1304
commit e39c26a95a
10 changed files with 99 additions and 81 deletions

View File

@@ -50,7 +50,7 @@ export default async (canvas, config) => {
GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_DST,
};
const timeUniforms = structs.from(`struct Time { seconds : f32; frames : i32; };`).Time;
const timeUniforms = structs.from(`struct Time { seconds : f32, frames : i32, };`).Time;
const timeBuffer = makeUniformBuffer(device, timeUniforms);
const context = {

View File

@@ -116,7 +116,7 @@ const getTypeData = (type, attributes, otherStructLayouts) => {
const parseAttributes = (str) => {
const attributes = {};
for (const attr of str.split(",").filter((attr) => attr.length > 0)) {
const match = attr.match(/@(\w+)(\((.*)\))?/); // @foo(bar)
const match = attr.match(/(\w+)(\((.*)\))?/); // foo(bar)
const [_, identifier, __, value] = match;
attributes[identifier] = value;
}
@@ -128,16 +128,33 @@ const parseStructLayout = (identifier, body, structLayouts) => {
let byteOffset = 0;
const lines = body
.trim()
.split(";")
.filter((s) => s.length > 0);
.split(",") // WGSL struct fields are currently delimited by commas...
.filter((s) => s.length > 0)
// ...but some commas separate elements between angle brackets, rather than between lines:
.reduce((existingLines, line, index) => {
if (index === 0) {
return [line];
}
const lastLine = existingLines[index - 1];
const angleBracketBalance = lastLine.split("<").length - lastLine.split(">").length;
if (angleBracketBalance !== 0) {
existingLines[index - 1] = `${lastLine},${line}`;
} else {
existingLines.push(line);
}
return existingLines;
}, []);
for (const line of lines) {
console.log(line);
const fieldMatch = line.match(/(\[\[(.*?)\]\])? ?(\w+) ?: ?(\[\[(.*?)\]\])? ?(.*)/); // @a(...) @b(...) foo : @c(...) @d(...) bar;
const fieldMatch = line.match(/(@(.*?))? ?(\w+) ?: ?(@(.*?))? ?(.*)/); // @a(...) @b(...) foo : @c(...) @d(...) bar;
const [_, __, leftAttributes, identifier, ___, rightAttributes, type] = fieldMatch;
const typeData = getTypeData(type, parseAttributes(rightAttributes ?? ""), structLayouts);
if (typeData == null) {
console.warn(`gSkipping struct ${identifier}.`);
console.warn(`Skipping struct ${identifier}.`);
return null;
}
@@ -166,6 +183,7 @@ const parseStructLayoutsFromShader = (wgsl) => {
const structLayouts = {};
const structMatches = Array.from(wgsl.matchAll(/struct (\w+) ?\{(.*?)\};/g)); // struct Foo {...}
for (const structMatch of structMatches) {
const [_, identifier, body] = structMatch;
const layout = parseStructLayout(identifier, body, structLayouts);

View File

@@ -1,8 +1,8 @@
let ONE_OVER_SQRT_2PI = 0.39894;
struct Config {
bloomRadius : f32;
direction : vec2<f32>;
bloomRadius : f32,
direction : vec2<f32>,
};
@group(0) @binding(0) var<uniform> config : Config;
@@ -11,7 +11,7 @@ struct Config {
@group(0) @binding(3) var outputTex : texture_storage_2d<rgba8unorm, write>;
struct ComputeInput {
@builtin(global_invocation_id) id : vec3<u32>;
@builtin(global_invocation_id) id : vec3<u32>,
};
fn gaussianPDF(x : f32) -> f32 {

View File

@@ -1,5 +1,5 @@
struct Config {
pyramidHeight : f32;
pyramidHeight : f32,
};
@group(0) @binding(0) var<uniform> config : Config;
@@ -16,7 +16,7 @@ struct Config {
@group(0) @binding(6) var outputTex : texture_storage_2d<rgba8unorm, write>;
struct ComputeInput {
@builtin(global_invocation_id) id : vec3<u32>;
@builtin(global_invocation_id) id : vec3<u32>,
};
@stage(compute) @workgroup_size(32, 1, 1) fn computeMain(input : ComputeInput) {

View File

@@ -2,8 +2,8 @@
@group(0) @binding(1) var tex : texture_2d<f32>;
struct VertOutput {
@builtin(position) Position : vec4<f32>;
@location(0) uv : vec2<f32>;
@builtin(position) Position : vec4<f32>,
@location(0) uv : vec2<f32>,
};
@stage(vertex) fn vertMain(@builtin(vertex_index) index : u32) -> VertOutput {

View File

@@ -1,5 +1,5 @@
struct Config {
bloomStrength : f32;
bloomStrength : f32,
};
@group(0) @binding(0) var<uniform> config : Config;
@@ -10,7 +10,7 @@ struct Config {
@group(0) @binding(5) var outputTex : texture_storage_2d<rgba8unorm, write>;
struct ComputeInput {
@builtin(global_invocation_id) id : vec3<u32>;
@builtin(global_invocation_id) id : vec3<u32>,
};
fn getBrightness(uv : vec2<f32>) -> vec4<f32> {

View File

@@ -1,16 +1,16 @@
struct Config {
bloomStrength : f32;
ditherMagnitude : f32;
backgroundColor : vec3<f32>;
bloomStrength : f32,
ditherMagnitude : f32,
backgroundColor : vec3<f32>,
};
struct Palette {
colors : array<vec3<f32>, 512>;
colors : array<vec3<f32>, 512>,
};
struct Time {
seconds : f32;
frames : i32;
seconds : f32,
frames : i32,
};
@group(0) @binding(0) var<uniform> config : Config;
@@ -22,7 +22,7 @@ struct Time {
@group(0) @binding(6) var outputTex : texture_storage_2d<rgba8unorm, write>;
struct ComputeInput {
@builtin(global_invocation_id) id : vec3<u32>;
@builtin(global_invocation_id) id : vec3<u32>,
};
let PI : f32 = 3.14159265359;

View File

@@ -3,60 +3,60 @@
struct Config {
// common properties used for compute and rendering
animationSpeed : f32;
glyphSequenceLength : i32;
glyphTextureGridSize : vec2<i32>;
glyphHeightToWidth : f32;
resurrectingCodeRatio : f32;
gridSize : vec2<f32>;
showComputationTexture : i32;
animationSpeed : f32,
glyphSequenceLength : i32,
glyphTextureGridSize : vec2<i32>,
glyphHeightToWidth : f32,
resurrectingCodeRatio : f32,
gridSize : vec2<f32>,
showComputationTexture : i32,
// compute-specific properties
brightnessThreshold : f32;
brightnessOverride : f32;
brightnessDecay : f32;
cursorEffectThreshold : f32;
cycleSpeed : f32;
cycleFrameSkip : i32;
fallSpeed : f32;
hasSun : i32;
hasThunder : i32;
raindropLength : f32;
rippleScale : f32;
rippleSpeed : f32;
rippleThickness : f32;
cycleStyle : i32;
rippleType : i32;
brightnessThreshold : f32,
brightnessOverride : f32,
brightnessDecay : f32,
cursorEffectThreshold : f32,
cycleSpeed : f32,
cycleFrameSkip : i32,
fallSpeed : f32,
hasSun : i32,
hasThunder : i32,
raindropLength : f32,
rippleScale : f32,
rippleSpeed : f32,
rippleThickness : f32,
cycleStyle : i32,
rippleType : i32,
// render-specific properties
forwardSpeed : f32;
glyphVerticalSpacing : f32;
glyphEdgeCrop : f32;
isPolar : i32;
density : f32;
slantScale : f32;
slantVec : vec2<f32>;
volumetric : i32;
loops : i32;
highPassThreshold : f32;
forwardSpeed : f32,
glyphVerticalSpacing : f32,
glyphEdgeCrop : f32,
isPolar : i32,
density : f32,
slantScale : f32,
slantVec : vec2<f32>,
volumetric : i32,
loops : i32,
highPassThreshold : f32,
};
// The properties that change over time get their own buffer.
struct Time {
seconds : f32;
frames : i32;
seconds : f32,
frames : i32,
};
// The properties related to the size of the canvas get their own buffer.
struct Scene {
screenSize : vec2<f32>;
camera : mat4x4<f32>;
transform : mat4x4<f32>;
screenSize : vec2<f32>,
camera : mat4x4<f32>,
transform : mat4x4<f32>,
};
// The array of cells that the compute shader updates, and the fragment shader draws.
struct CellData {
cells: array<vec4<f32>>;
cells: array<vec4<f32>>,
};
// Shared bindings
@@ -75,23 +75,23 @@ struct CellData {
// Shader params
struct ComputeInput {
@builtin(global_invocation_id) id : vec3<u32>;
@builtin(global_invocation_id) id : vec3<u32>,
};
struct VertInput {
@builtin(vertex_index) index : u32;
@builtin(vertex_index) index : u32,
};
struct VertOutput {
@builtin(position) Position : vec4<f32>;
@location(0) uv : vec2<f32>;
@location(1) channel : vec3<f32>;
@location(2) glyph : vec4<f32>;
@builtin(position) Position : vec4<f32>,
@location(0) uv : vec2<f32>,
@location(1) channel : vec3<f32>,
@location(2) glyph : vec4<f32>,
};
struct FragOutput {
@location(0) color : vec4<f32>;
@location(1) highPassColor : vec4<f32>;
@location(0) color : vec4<f32>,
@location(1) highPassColor : vec4<f32>,
};
// Constants

View File

@@ -1,12 +1,12 @@
struct Config {
bloomStrength : f32;
ditherMagnitude : f32;
backgroundColor : vec3<f32>;
bloomStrength : f32,
ditherMagnitude : f32,
backgroundColor : vec3<f32>,
};
struct Time {
seconds : f32;
frames : i32;
seconds : f32,
frames : i32,
};
@group(0) @binding(0) var<uniform> config : Config;
@@ -17,7 +17,7 @@ struct Time {
@group(0) @binding(5) var outputTex : texture_storage_2d<rgba8unorm, write>;
struct ComputeInput {
@builtin(global_invocation_id) id : vec3<u32>;
@builtin(global_invocation_id) id : vec3<u32>,
};
let PI : f32 = 3.14159265359;

View File

@@ -1,12 +1,12 @@
struct Config {
bloomStrength : f32;
ditherMagnitude : f32;
backgroundColor : vec3<f32>;
bloomStrength : f32,
ditherMagnitude : f32,
backgroundColor : vec3<f32>,
};
struct Time {
seconds : f32;
frames : i32;
seconds : f32,
frames : i32,
};
@group(0) @binding(0) var<uniform> config : Config;
@@ -18,7 +18,7 @@ struct Time {
@group(0) @binding(6) var outputTex : texture_storage_2d<rgba8unorm, write>;
struct ComputeInput {
@builtin(global_invocation_id) id : vec3<u32>;
@builtin(global_invocation_id) id : vec3<u32>,
};
let PI : f32 = 3.14159265359;