From e39c26a95abad276de4c3f8172837146a4afcd02 Mon Sep 17 00:00:00 2001 From: Rezmason Date: Sat, 30 Apr 2022 18:00:35 -0700 Subject: [PATCH] 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. --- js/webgpu/main.js | 2 +- lib/gpu-buffer.js | 30 ++++++++-- shaders/wgsl/bloomBlur.wgsl | 6 +- shaders/wgsl/bloomCombine.wgsl | 4 +- shaders/wgsl/endPass.wgsl | 4 +- shaders/wgsl/imagePass.wgsl | 4 +- shaders/wgsl/palettePass.wgsl | 14 ++--- shaders/wgsl/rainPass.wgsl | 92 +++++++++++++++--------------- shaders/wgsl/resurrectionPass.wgsl | 12 ++-- shaders/wgsl/stripePass.wgsl | 12 ++-- 10 files changed, 99 insertions(+), 81 deletions(-) diff --git a/js/webgpu/main.js b/js/webgpu/main.js index 8a95dba..be08661 100644 --- a/js/webgpu/main.js +++ b/js/webgpu/main.js @@ -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 = { diff --git a/lib/gpu-buffer.js b/lib/gpu-buffer.js index b3cb94a..d1b9d13 100644 --- a/lib/gpu-buffer.js +++ b/lib/gpu-buffer.js @@ -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); diff --git a/shaders/wgsl/bloomBlur.wgsl b/shaders/wgsl/bloomBlur.wgsl index 0c2d796..8d413dd 100644 --- a/shaders/wgsl/bloomBlur.wgsl +++ b/shaders/wgsl/bloomBlur.wgsl @@ -1,8 +1,8 @@ let ONE_OVER_SQRT_2PI = 0.39894; struct Config { - bloomRadius : f32; - direction : vec2; + bloomRadius : f32, + direction : vec2, }; @group(0) @binding(0) var config : Config; @@ -11,7 +11,7 @@ struct Config { @group(0) @binding(3) var outputTex : texture_storage_2d; struct ComputeInput { - @builtin(global_invocation_id) id : vec3; + @builtin(global_invocation_id) id : vec3, }; fn gaussianPDF(x : f32) -> f32 { diff --git a/shaders/wgsl/bloomCombine.wgsl b/shaders/wgsl/bloomCombine.wgsl index d6f65d2..1bbe978 100644 --- a/shaders/wgsl/bloomCombine.wgsl +++ b/shaders/wgsl/bloomCombine.wgsl @@ -1,5 +1,5 @@ struct Config { - pyramidHeight : f32; + pyramidHeight : f32, }; @group(0) @binding(0) var config : Config; @@ -16,7 +16,7 @@ struct Config { @group(0) @binding(6) var outputTex : texture_storage_2d; struct ComputeInput { - @builtin(global_invocation_id) id : vec3; + @builtin(global_invocation_id) id : vec3, }; @stage(compute) @workgroup_size(32, 1, 1) fn computeMain(input : ComputeInput) { diff --git a/shaders/wgsl/endPass.wgsl b/shaders/wgsl/endPass.wgsl index dab4468..c62363f 100644 --- a/shaders/wgsl/endPass.wgsl +++ b/shaders/wgsl/endPass.wgsl @@ -2,8 +2,8 @@ @group(0) @binding(1) var tex : texture_2d; struct VertOutput { - @builtin(position) Position : vec4; - @location(0) uv : vec2; + @builtin(position) Position : vec4, + @location(0) uv : vec2, }; @stage(vertex) fn vertMain(@builtin(vertex_index) index : u32) -> VertOutput { diff --git a/shaders/wgsl/imagePass.wgsl b/shaders/wgsl/imagePass.wgsl index 7bb1110..5df32bc 100644 --- a/shaders/wgsl/imagePass.wgsl +++ b/shaders/wgsl/imagePass.wgsl @@ -1,5 +1,5 @@ struct Config { - bloomStrength : f32; + bloomStrength : f32, }; @group(0) @binding(0) var config : Config; @@ -10,7 +10,7 @@ struct Config { @group(0) @binding(5) var outputTex : texture_storage_2d; struct ComputeInput { - @builtin(global_invocation_id) id : vec3; + @builtin(global_invocation_id) id : vec3, }; fn getBrightness(uv : vec2) -> vec4 { diff --git a/shaders/wgsl/palettePass.wgsl b/shaders/wgsl/palettePass.wgsl index 672baf7..aac8b9d 100644 --- a/shaders/wgsl/palettePass.wgsl +++ b/shaders/wgsl/palettePass.wgsl @@ -1,16 +1,16 @@ struct Config { - bloomStrength : f32; - ditherMagnitude : f32; - backgroundColor : vec3; + bloomStrength : f32, + ditherMagnitude : f32, + backgroundColor : vec3, }; struct Palette { - colors : array, 512>; + colors : array, 512>, }; struct Time { - seconds : f32; - frames : i32; + seconds : f32, + frames : i32, }; @group(0) @binding(0) var config : Config; @@ -22,7 +22,7 @@ struct Time { @group(0) @binding(6) var outputTex : texture_storage_2d; struct ComputeInput { - @builtin(global_invocation_id) id : vec3; + @builtin(global_invocation_id) id : vec3, }; let PI : f32 = 3.14159265359; diff --git a/shaders/wgsl/rainPass.wgsl b/shaders/wgsl/rainPass.wgsl index 1df1a98..83572e5 100644 --- a/shaders/wgsl/rainPass.wgsl +++ b/shaders/wgsl/rainPass.wgsl @@ -3,60 +3,60 @@ struct Config { // common properties used for compute and rendering - animationSpeed : f32; - glyphSequenceLength : i32; - glyphTextureGridSize : vec2; - glyphHeightToWidth : f32; - resurrectingCodeRatio : f32; - gridSize : vec2; - showComputationTexture : i32; + animationSpeed : f32, + glyphSequenceLength : i32, + glyphTextureGridSize : vec2, + glyphHeightToWidth : f32, + resurrectingCodeRatio : f32, + gridSize : vec2, + 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; - volumetric : i32; - loops : i32; - highPassThreshold : f32; + forwardSpeed : f32, + glyphVerticalSpacing : f32, + glyphEdgeCrop : f32, + isPolar : i32, + density : f32, + slantScale : f32, + slantVec : vec2, + 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; - camera : mat4x4; - transform : mat4x4; + screenSize : vec2, + camera : mat4x4, + transform : mat4x4, }; // The array of cells that the compute shader updates, and the fragment shader draws. struct CellData { - cells: array>; + cells: array>, }; // Shared bindings @@ -75,23 +75,23 @@ struct CellData { // Shader params struct ComputeInput { - @builtin(global_invocation_id) id : vec3; + @builtin(global_invocation_id) id : vec3, }; struct VertInput { - @builtin(vertex_index) index : u32; + @builtin(vertex_index) index : u32, }; struct VertOutput { - @builtin(position) Position : vec4; - @location(0) uv : vec2; - @location(1) channel : vec3; - @location(2) glyph : vec4; + @builtin(position) Position : vec4, + @location(0) uv : vec2, + @location(1) channel : vec3, + @location(2) glyph : vec4, }; struct FragOutput { - @location(0) color : vec4; - @location(1) highPassColor : vec4; + @location(0) color : vec4, + @location(1) highPassColor : vec4, }; // Constants diff --git a/shaders/wgsl/resurrectionPass.wgsl b/shaders/wgsl/resurrectionPass.wgsl index ea4e86a..a9ac073 100644 --- a/shaders/wgsl/resurrectionPass.wgsl +++ b/shaders/wgsl/resurrectionPass.wgsl @@ -1,12 +1,12 @@ struct Config { - bloomStrength : f32; - ditherMagnitude : f32; - backgroundColor : vec3; + bloomStrength : f32, + ditherMagnitude : f32, + backgroundColor : vec3, }; struct Time { - seconds : f32; - frames : i32; + seconds : f32, + frames : i32, }; @group(0) @binding(0) var config : Config; @@ -17,7 +17,7 @@ struct Time { @group(0) @binding(5) var outputTex : texture_storage_2d; struct ComputeInput { - @builtin(global_invocation_id) id : vec3; + @builtin(global_invocation_id) id : vec3, }; let PI : f32 = 3.14159265359; diff --git a/shaders/wgsl/stripePass.wgsl b/shaders/wgsl/stripePass.wgsl index 4a1a03d..7dbe76f 100644 --- a/shaders/wgsl/stripePass.wgsl +++ b/shaders/wgsl/stripePass.wgsl @@ -1,12 +1,12 @@ struct Config { - bloomStrength : f32; - ditherMagnitude : f32; - backgroundColor : vec3; + bloomStrength : f32, + ditherMagnitude : f32, + backgroundColor : vec3, }; struct Time { - seconds : f32; - frames : i32; + seconds : f32, + frames : i32, }; @group(0) @binding(0) var config : Config; @@ -18,7 +18,7 @@ struct Time { @group(0) @binding(6) var outputTex : texture_storage_2d; struct ComputeInput { - @builtin(global_invocation_id) id : vec3; + @builtin(global_invocation_id) id : vec3, }; let PI : f32 = 3.14159265359;