diff --git a/TODO.txt b/TODO.txt index 6d65f06..ce37fb3 100644 --- a/TODO.txt +++ b/TODO.txt @@ -59,14 +59,9 @@ WebGPU Get rid of end pass once it's possible to copy a bgra8unorm to a canvas texture Switch to rgba32float somehow? Why isn't this straightforward? - - Best practices - https://www.youtube.com/watch?v=wYAvVUFQP2M&t=1360s - Use labels and debug groups everywhere - Create pipelines async-await - Use implicit pipeline layouts sparingly - I'm using implicit pipeline layouts - What would explicit layouts look like? + Try shorthand + Share a bind group and layout just for time? + Try using a buffer for the stripe pass 1D texture Improve loop support @@ -89,5 +84,7 @@ Deja vu effect: flashing rows Then use a thunder-like pattern to show and hide the flash gpu-buffer, working title + Support type aliasing (type Q = array) + Support shorthand (vec4f) Build mocha tests, example project Give it its own repo, microsite diff --git a/js/regl/main.js b/js/regl/main.js index 1e8da12..635fe6c 100644 --- a/js/regl/main.js +++ b/js/regl/main.js @@ -34,7 +34,7 @@ const loadJS = (src) => }); export default async (canvas, config) => { - await Promise.all([loadJS("lib/regl.js"), loadJS("lib/gl-matrix.js")]); + await Promise.all([loadJS("lib/regl.min.js"), loadJS("lib/gl-matrix.js")]); const resize = () => { canvas.width = Math.ceil(canvas.clientWidth * config.resolution); diff --git a/js/webgpu/bloomPass.js b/js/webgpu/bloomPass.js index f8e3ccb..9d653b9 100644 --- a/js/webgpu/bloomPass.js +++ b/js/webgpu/bloomPass.js @@ -44,7 +44,7 @@ export default ({ config, device }) => { // If there's no bloom to apply, return a no-op pass with an empty bloom texture if (!enabled) { const emptyTexture = makeComputeTarget(device, [1, 1]); - return makePass(null, (size, inputs) => ({ ...inputs, bloom: emptyTexture })); + return makePass("No Bloom", null, (size, inputs) => ({ ...inputs, bloom: emptyTexture })); } const assets = [loadShader(device, "shaders/wgsl/bloomBlur.wgsl"), loadShader(device, "shaders/wgsl/bloomCombine.wgsl")]; @@ -74,21 +74,23 @@ export default ({ config, device }) => { const loaded = (async () => { const [blurShader, combineShader] = await Promise.all(assets); - blurPipeline = device.createComputePipeline({ - layout: "auto", - compute: { - module: blurShader.module, - entryPoint: "computeMain", - }, - }); + [blurPipeline, combinePipeline] = await Promise.all([ + device.createComputePipeline({ + layout: "auto", + compute: { + module: blurShader.module, + entryPoint: "computeMain", + }, + }), - combinePipeline = device.createComputePipeline({ - layout: "auto", - compute: { - module: combineShader.module, - entryPoint: "computeMain", - }, - }); + device.createComputePipeline({ + layout: "auto", + compute: { + module: combineShader.module, + entryPoint: "computeMain", + }, + }), + ]); const blurUniforms = structs.from(blurShader.code).Config; hBlurBuffer = makeUniformBuffer(device, blurUniforms, { bloomRadius, direction: [1, 0] }); @@ -152,5 +154,5 @@ export default ({ config, device }) => { computePass.end(); }; - return makePass(loaded, build, run); + return makePass("Bloom", loaded, build, run); }; diff --git a/js/webgpu/endPass.js b/js/webgpu/endPass.js index b539306..5df3fb7 100644 --- a/js/webgpu/endPass.js +++ b/js/webgpu/endPass.js @@ -26,7 +26,7 @@ export default ({ device, canvasFormat, canvasContext }) => { const loaded = (async () => { const [imageShader] = await Promise.all(assets); - renderPipeline = device.createRenderPipeline({ + renderPipeline = await device.createRenderPipelineAsync({ layout: "auto", vertex: { module: imageShader.module, @@ -58,5 +58,5 @@ export default ({ device, canvasFormat, canvasContext }) => { renderPass.end(); }; - return makePass(loaded, build, run); + return makePass("End", loaded, build, run); }; diff --git a/js/webgpu/imagePass.js b/js/webgpu/imagePass.js index 0ef1959..89c8321 100644 --- a/js/webgpu/imagePass.js +++ b/js/webgpu/imagePass.js @@ -26,7 +26,7 @@ export default ({ config, device }) => { backgroundTex = bgTex; - computePipeline = device.createComputePipeline({ + computePipeline = await device.createComputePipelineAsync({ layout: "auto", compute: { module: imageShader.module, @@ -61,5 +61,5 @@ export default ({ config, device }) => { computePass.end(); }; - return makePass(loaded, build, run); + return makePass("Image", loaded, build, run); }; diff --git a/js/webgpu/mirrorPass.js b/js/webgpu/mirrorPass.js index c9c7692..371b75b 100644 --- a/js/webgpu/mirrorPass.js +++ b/js/webgpu/mirrorPass.js @@ -18,14 +18,6 @@ window.onclick = (e) => { touchesChanged = true; }; -/* -uniforms: { - touches: () => touches, - aspectRatio: () => aspectRatio, - cameraAspectRatio, -} -*/ - export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) => { const assets = [loadShader(device, "shaders/wgsl/mirrorPass.wgsl")]; @@ -47,7 +39,7 @@ export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) => const loaded = (async () => { const [mirrorShader] = await Promise.all(assets); - computePipeline = device.createComputePipeline({ + computePipeline = await device.createComputePipelineAsync({ layout: "auto", compute: { module: mirrorShader.module, @@ -105,5 +97,5 @@ export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) => start = Date.now(); - return makePass(loaded, build, run); + return makePass("Mirror", loaded, build, run); }; diff --git a/js/webgpu/palettePass.js b/js/webgpu/palettePass.js index be13978..e6ac123 100644 --- a/js/webgpu/palettePass.js +++ b/js/webgpu/palettePass.js @@ -93,7 +93,7 @@ export default ({ config, device, timeBuffer }) => { const loaded = (async () => { const [paletteShader] = await Promise.all(assets); - computePipeline = device.createComputePipeline({ + computePipeline = await device.createComputePipelineAsync({ layout: "auto", compute: { module: paletteShader.module, @@ -137,5 +137,5 @@ export default ({ config, device, timeBuffer }) => { computePass.end(); }; - return makePass(loaded, build, run); + return makePass("Palette", loaded, build, run); }; diff --git a/js/webgpu/rainPass.js b/js/webgpu/rainPass.js index 2b6d795..8a11f93 100644 --- a/js/webgpu/rainPass.js +++ b/js/webgpu/rainPass.js @@ -104,47 +104,49 @@ export default ({ config, device, timeBuffer }) => { sceneUniforms = rainShaderUniforms.Scene; sceneBuffer = makeUniformBuffer(device, sceneUniforms); - computePipeline = device.createComputePipeline({ - layout: "auto", - compute: { - module: rainShader.module, - entryPoint: "computeMain", - }, - }); - const additiveBlendComponent = { operation: "add", srcFactor: "one", dstFactor: "one", }; - renderPipeline = device.createRenderPipeline({ - layout: "auto", - vertex: { - module: rainShader.module, - entryPoint: "vertMain", - }, - fragment: { - module: rainShader.module, - entryPoint: "fragMain", - targets: [ - { - format: renderFormat, - blend: { - color: additiveBlendComponent, - alpha: additiveBlendComponent, + [computePipeline, renderPipeline] = await Promise.all([ + device.createComputePipelineAsync({ + layout: "auto", + compute: { + module: rainShader.module, + entryPoint: "computeMain", + }, + }), + + device.createRenderPipelineAsync({ + layout: "auto", + vertex: { + module: rainShader.module, + entryPoint: "vertMain", + }, + fragment: { + module: rainShader.module, + entryPoint: "fragMain", + targets: [ + { + format: renderFormat, + blend: { + color: additiveBlendComponent, + alpha: additiveBlendComponent, + }, }, - }, - { - format: renderFormat, - blend: { - color: additiveBlendComponent, - alpha: additiveBlendComponent, + { + format: renderFormat, + blend: { + color: additiveBlendComponent, + alpha: additiveBlendComponent, + }, }, - }, - ], - }, - }); + ], + }, + }), + ]); computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer]); renderBindGroup = makeBindGroup(device, renderPipeline, 0, [configBuffer, timeBuffer, sceneBuffer, linearSampler, msdfTexture.createView(), cellsBuffer]); @@ -196,5 +198,5 @@ export default ({ config, device, timeBuffer }) => { renderPass.end(); }; - return makePass(loaded, build, run); + return makePass("Rain", loaded, build, run); }; diff --git a/js/webgpu/stripePass.js b/js/webgpu/stripePass.js index b593838..b83123e 100644 --- a/js/webgpu/stripePass.js +++ b/js/webgpu/stripePass.js @@ -65,7 +65,8 @@ export default ({ config, device, timeBuffer }) => { const loaded = (async () => { const [stripeShader] = await Promise.all(assets); - computePipeline = device.createComputePipeline({ + computePipeline = await device.createComputePipelineAsync({ + layout: "auto", compute: { module: stripeShader.module, entryPoint: "computeMain", @@ -110,5 +111,5 @@ export default ({ config, device, timeBuffer }) => { computePass.end(); }; - return makePass(loaded, build, run); + return makePass("Stripe", loaded, build, run); }; diff --git a/js/webgpu/utils.js b/js/webgpu/utils.js index 321aafd..ecee5d3 100644 --- a/js/webgpu/utils.js +++ b/js/webgpu/utils.js @@ -1,4 +1,6 @@ /* +// TODO: switch back to this impl once it doesn't break on FF Nightly + const loadTexture = async (device, url) => { const response = await fetch(url); const data = await response.blob(); @@ -105,10 +107,14 @@ const makeBindGroup = (device, pipeline, index, entries) => })), }); -const makePass = (loaded, build, run) => ({ +const makePass = (name, loaded, build, run) => ({ loaded: loaded ?? Promise.resolve(), build: build ?? ((size, inputs) => inputs), - run: run ?? (() => {}), + run: (encoder) => { + encoder.pushDebugGroup(`Pass "${name}"`); + run?.(encoder); + encoder.popDebugGroup(); + }, }); const makePipeline = async (context, steps) => {