From 415ffa77ee674a3095a045737714ae5caaa9723a Mon Sep 17 00:00:00 2001 From: Rezmason Date: Mon, 8 Nov 2021 03:01:46 -0800 Subject: [PATCH] Driving more uniforms.read calls from the actual shaders. --- TODO.txt | 15 ++++++++------- js/webgpu/imagePass.js | 1 - js/webgpu/palettePass.js | 17 ++++++++++------- js/webgpu/rainPass.js | 4 +--- js/webgpu/resurrectionPass.js | 8 ++++---- js/webgpu/stripePass.js | 8 ++++---- js/webgpu/utils.js | 1 - lib/gpu-uniforms.js | 4 ++++ 8 files changed, 31 insertions(+), 27 deletions(-) diff --git a/TODO.txt b/TODO.txt index 8da41ac..9a8f1a2 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,17 +3,18 @@ TODO: WebGPU blur pass - Cleanup - Maybe buffer layouts and buffers can be consolidated somehow - Update links in issues Try to change post processing to compute shaders once they're easier to support - gpu-uniforms (was "std140") - Resolve the memory positions of the fields in the parse layouts - Resolve each layout into a Proxy around an ArrayBuffer and three mapped typedarrays - Document and share it + gpu-uniforms + Is this an adequate name for it? Can't it be useful for non-uniform-related things? + Resolve the remaining to-dos + Try and drive use it for the palette color buffer + Test it + Demo it to others + Make improvements + License it and put it somewhere else Write an explanation of the rain pass (and include images) diff --git a/js/webgpu/imagePass.js b/js/webgpu/imagePass.js index d7ee681..56ffbd7 100644 --- a/js/webgpu/imagePass.js +++ b/js/webgpu/imagePass.js @@ -8,7 +8,6 @@ const numVerticesPerQuad = 2 * 3; export default (context, getInputs) => { const { config, adapter, device, canvasContext } = context; - const ditherMagnitude = 0.05; const linearSampler = device.createSampler({ magFilter: "linear", diff --git a/js/webgpu/palettePass.js b/js/webgpu/palettePass.js index 3c93e61..96d923c 100644 --- a/js/webgpu/palettePass.js +++ b/js/webgpu/palettePass.js @@ -17,7 +17,7 @@ const colorToRGB = ([hue, saturation, lightness]) => { const numVerticesPerQuad = 2 * 3; -const makePalette = (device, entries) => { +const makePalette = (device, paletteUniforms, entries) => { const PALETTE_SIZE = 512; const paletteColors = Array(PALETTE_SIZE); @@ -79,12 +79,6 @@ const makePalette = (device, entries) => { export default (context, getInputs) => { const { config, adapter, device, canvasContext, timeBuffer } = context; - const ditherMagnitude = 0.05; - - const configUniforms = uniforms.read(`struct Config { ditherMagnitude : f32; backgroundColor: vec3; };`).Config; - const configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude, backgroundColor: config.backgroundColor }); - - const paletteBuffer = makePalette(device, config.paletteEntries); const linearSampler = device.createSampler({ magFilter: "linear", @@ -104,6 +98,8 @@ export default (context, getInputs) => { const presentationFormat = canvasContext.getPreferredFormat(adapter); let renderPipeline; + let configBuffer; + let paletteBuffer; let output; const assets = [loadShader(device, "shaders/wgsl/palettePass.wgsl")]; @@ -126,6 +122,13 @@ export default (context, getInputs) => { ], }, }); + + const paletteShaderUniforms = uniforms.read(paletteShader.code); + const configUniforms = paletteShaderUniforms.Config; + configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor }); + + const paletteUniforms = paletteShaderUniforms.Palette; + paletteBuffer = makePalette(device, paletteUniforms, config.paletteEntries); })(); const setSize = (width, height) => { diff --git a/js/webgpu/rainPass.js b/js/webgpu/rainPass.js index 2c5f43a..42ce1e6 100644 --- a/js/webgpu/rainPass.js +++ b/js/webgpu/rainPass.js @@ -46,10 +46,8 @@ export default (context, getInputs) => { // rather than a single quad for our geometry const numQuads = config.volumetric ? numCells : 1; - // TODO: uniforms should be updated to provide this too - const cellsBuffer = device.createBuffer({ - size: numCells * 4 * Float32Array.BYTES_PER_ELEMENT, + size: numCells * uniforms.byteSizeOf("vec4"), usage: GPUBufferUsage.STORAGE, }); diff --git a/js/webgpu/resurrectionPass.js b/js/webgpu/resurrectionPass.js index b55f895..f4b8eb7 100644 --- a/js/webgpu/resurrectionPass.js +++ b/js/webgpu/resurrectionPass.js @@ -13,10 +13,6 @@ const numVerticesPerQuad = 2 * 3; export default (context, getInputs) => { const { config, adapter, device, canvasContext, timeBuffer } = context; - const ditherMagnitude = 0.05; - - const configUniforms = uniforms.read(`struct Config { ditherMagnitude : f32; backgroundColor: vec3; };`).Config; - const configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude, backgroundColor: config.backgroundColor }); const linearSampler = device.createSampler({ magFilter: "linear", @@ -36,6 +32,7 @@ export default (context, getInputs) => { const presentationFormat = canvasContext.getPreferredFormat(adapter); let renderPipeline; + let configBuffer; let output; const assets = [loadShader(device, "shaders/wgsl/resurrectionPass.wgsl")]; @@ -58,6 +55,9 @@ export default (context, getInputs) => { ], }, }); + + const configUniforms = uniforms.read(resurrectionShader.code).Config; + configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor }); })(); const setSize = (width, height) => { diff --git a/js/webgpu/stripePass.js b/js/webgpu/stripePass.js index df39f6f..3320545 100644 --- a/js/webgpu/stripePass.js +++ b/js/webgpu/stripePass.js @@ -39,10 +39,6 @@ const numVerticesPerQuad = 2 * 3; export default (context, getInputs) => { const { config, adapter, device, canvasContext, timeBuffer } = context; - const ditherMagnitude = 0.05; - - const configUniforms = uniforms.read(`struct Config { ditherMagnitude : f32; backgroundColor: vec3; };`).Config; - const configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude, backgroundColor: config.backgroundColor }); // Expand and convert stripe colors into 1D texture data const stripeColors = @@ -71,6 +67,7 @@ export default (context, getInputs) => { const presentationFormat = canvasContext.getPreferredFormat(adapter); let renderPipeline; + let configBuffer; let output; const assets = [loadShader(device, "shaders/wgsl/stripePass.wgsl")]; @@ -93,6 +90,9 @@ export default (context, getInputs) => { ], }, }); + + const configUniforms = uniforms.read(stripeShader.code).Config; + configBuffer = makeUniformBuffer(device, configUniforms, { ditherMagnitude: 0.05, backgroundColor: config.backgroundColor }); })(); const setSize = (width, height) => { diff --git a/js/webgpu/utils.js b/js/webgpu/utils.js index 0e0eb0e..a180f65 100644 --- a/js/webgpu/utils.js +++ b/js/webgpu/utils.js @@ -32,7 +32,6 @@ const makePassFBO = (device, width, height, format = "rgba8unorm") => size: [width, height, 1], format, usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT, - // TODO: whittle these down }); const loadShader = async (device, url) => { diff --git a/lib/gpu-uniforms.js b/lib/gpu-uniforms.js index 7747af6..e996c36 100644 --- a/lib/gpu-uniforms.js +++ b/lib/gpu-uniforms.js @@ -211,9 +211,13 @@ const makeGenerator = (layout, structLayouts) => { const api = Object.freeze({ read: (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;