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, 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 timeBuffer = makeUniformBuffer(device, timeUniforms);
const context = { const context = {

View File

@@ -116,7 +116,7 @@ const getTypeData = (type, attributes, otherStructLayouts) => {
const parseAttributes = (str) => { const parseAttributes = (str) => {
const attributes = {}; const attributes = {};
for (const attr of str.split(",").filter((attr) => attr.length > 0)) { 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; const [_, identifier, __, value] = match;
attributes[identifier] = value; attributes[identifier] = value;
} }
@@ -128,16 +128,33 @@ const parseStructLayout = (identifier, body, structLayouts) => {
let byteOffset = 0; let byteOffset = 0;
const lines = body const lines = body
.trim() .trim()
.split(";") .split(",") // WGSL struct fields are currently delimited by commas...
.filter((s) => s.length > 0); .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) { 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 [_, __, leftAttributes, identifier, ___, rightAttributes, type] = fieldMatch;
const typeData = getTypeData(type, parseAttributes(rightAttributes ?? ""), structLayouts); const typeData = getTypeData(type, parseAttributes(rightAttributes ?? ""), structLayouts);
if (typeData == null) { if (typeData == null) {
console.warn(`gSkipping struct ${identifier}.`); console.warn(`Skipping struct ${identifier}.`);
return null; return null;
} }
@@ -166,6 +183,7 @@ const parseStructLayoutsFromShader = (wgsl) => {
const structLayouts = {}; const structLayouts = {};
const structMatches = Array.from(wgsl.matchAll(/struct (\w+) ?\{(.*?)\};/g)); // struct Foo {...} const structMatches = Array.from(wgsl.matchAll(/struct (\w+) ?\{(.*?)\};/g)); // struct Foo {...}
for (const structMatch of structMatches) { for (const structMatch of structMatches) {
const [_, identifier, body] = structMatch; const [_, identifier, body] = structMatch;
const layout = parseStructLayout(identifier, body, structLayouts); const layout = parseStructLayout(identifier, body, structLayouts);

View File

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

View File

@@ -1,5 +1,5 @@
struct Config { struct Config {
pyramidHeight : f32; pyramidHeight : f32,
}; };
@group(0) @binding(0) var<uniform> config : Config; @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>; @group(0) @binding(6) var outputTex : texture_storage_2d<rgba8unorm, write>;
struct ComputeInput { 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) { @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>; @group(0) @binding(1) var tex : texture_2d<f32>;
struct VertOutput { struct VertOutput {
@builtin(position) Position : vec4<f32>; @builtin(position) Position : vec4<f32>,
@location(0) uv : vec2<f32>; @location(0) uv : vec2<f32>,
}; };
@stage(vertex) fn vertMain(@builtin(vertex_index) index : u32) -> VertOutput { @stage(vertex) fn vertMain(@builtin(vertex_index) index : u32) -> VertOutput {

View File

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

View File

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

View File

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

View File

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

View File

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