Adding named debug groups to the WebGPU passes, and switching the pipeline create calls to the async methods

This commit is contained in:
Rezmason
2022-09-11 15:03:51 -07:00
parent c4fe2c53e4
commit ec831ce6f1
10 changed files with 79 additions and 79 deletions

View File

@@ -59,14 +59,9 @@ WebGPU
Get rid of end pass once it's possible to copy a bgra8unorm to a canvas texture Get rid of end pass once it's possible to copy a bgra8unorm to a canvas texture
Switch to rgba32float somehow? Switch to rgba32float somehow?
Why isn't this straightforward? Why isn't this straightforward?
Try shorthand
Best practices Share a bind group and layout just for time?
https://www.youtube.com/watch?v=wYAvVUFQP2M&t=1360s Try using a buffer for the stripe pass 1D texture
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?
Improve loop support Improve loop support
@@ -89,5 +84,7 @@ Deja vu effect: flashing rows
Then use a thunder-like pattern to show and hide the flash Then use a thunder-like pattern to show and hide the flash
gpu-buffer, working title gpu-buffer, working title
Support type aliasing (type Q = array<i32, 5>)
Support shorthand (vec4f)
Build mocha tests, example project Build mocha tests, example project
Give it its own repo, microsite Give it its own repo, microsite

View File

@@ -34,7 +34,7 @@ const loadJS = (src) =>
}); });
export default async (canvas, config) => { 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 = () => { const resize = () => {
canvas.width = Math.ceil(canvas.clientWidth * config.resolution); canvas.width = Math.ceil(canvas.clientWidth * config.resolution);

View File

@@ -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 there's no bloom to apply, return a no-op pass with an empty bloom texture
if (!enabled) { if (!enabled) {
const emptyTexture = makeComputeTarget(device, [1, 1]); 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")]; 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 loaded = (async () => {
const [blurShader, combineShader] = await Promise.all(assets); const [blurShader, combineShader] = await Promise.all(assets);
blurPipeline = device.createComputePipeline({ [blurPipeline, combinePipeline] = await Promise.all([
layout: "auto", device.createComputePipeline({
compute: { layout: "auto",
module: blurShader.module, compute: {
entryPoint: "computeMain", module: blurShader.module,
}, entryPoint: "computeMain",
}); },
}),
combinePipeline = device.createComputePipeline({ device.createComputePipeline({
layout: "auto", layout: "auto",
compute: { compute: {
module: combineShader.module, module: combineShader.module,
entryPoint: "computeMain", entryPoint: "computeMain",
}, },
}); }),
]);
const blurUniforms = structs.from(blurShader.code).Config; const blurUniforms = structs.from(blurShader.code).Config;
hBlurBuffer = makeUniformBuffer(device, blurUniforms, { bloomRadius, direction: [1, 0] }); hBlurBuffer = makeUniformBuffer(device, blurUniforms, { bloomRadius, direction: [1, 0] });
@@ -152,5 +154,5 @@ export default ({ config, device }) => {
computePass.end(); computePass.end();
}; };
return makePass(loaded, build, run); return makePass("Bloom", loaded, build, run);
}; };

View File

@@ -26,7 +26,7 @@ export default ({ device, canvasFormat, canvasContext }) => {
const loaded = (async () => { const loaded = (async () => {
const [imageShader] = await Promise.all(assets); const [imageShader] = await Promise.all(assets);
renderPipeline = device.createRenderPipeline({ renderPipeline = await device.createRenderPipelineAsync({
layout: "auto", layout: "auto",
vertex: { vertex: {
module: imageShader.module, module: imageShader.module,
@@ -58,5 +58,5 @@ export default ({ device, canvasFormat, canvasContext }) => {
renderPass.end(); renderPass.end();
}; };
return makePass(loaded, build, run); return makePass("End", loaded, build, run);
}; };

View File

@@ -26,7 +26,7 @@ export default ({ config, device }) => {
backgroundTex = bgTex; backgroundTex = bgTex;
computePipeline = device.createComputePipeline({ computePipeline = await device.createComputePipelineAsync({
layout: "auto", layout: "auto",
compute: { compute: {
module: imageShader.module, module: imageShader.module,
@@ -61,5 +61,5 @@ export default ({ config, device }) => {
computePass.end(); computePass.end();
}; };
return makePass(loaded, build, run); return makePass("Image", loaded, build, run);
}; };

View File

@@ -18,14 +18,6 @@ window.onclick = (e) => {
touchesChanged = true; touchesChanged = true;
}; };
/*
uniforms: {
touches: () => touches,
aspectRatio: () => aspectRatio,
cameraAspectRatio,
}
*/
export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) => { export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) => {
const assets = [loadShader(device, "shaders/wgsl/mirrorPass.wgsl")]; const assets = [loadShader(device, "shaders/wgsl/mirrorPass.wgsl")];
@@ -47,7 +39,7 @@ export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) =>
const loaded = (async () => { const loaded = (async () => {
const [mirrorShader] = await Promise.all(assets); const [mirrorShader] = await Promise.all(assets);
computePipeline = device.createComputePipeline({ computePipeline = await device.createComputePipelineAsync({
layout: "auto", layout: "auto",
compute: { compute: {
module: mirrorShader.module, module: mirrorShader.module,
@@ -105,5 +97,5 @@ export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) =>
start = Date.now(); start = Date.now();
return makePass(loaded, build, run); return makePass("Mirror", loaded, build, run);
}; };

View File

@@ -93,7 +93,7 @@ export default ({ config, device, timeBuffer }) => {
const loaded = (async () => { const loaded = (async () => {
const [paletteShader] = await Promise.all(assets); const [paletteShader] = await Promise.all(assets);
computePipeline = device.createComputePipeline({ computePipeline = await device.createComputePipelineAsync({
layout: "auto", layout: "auto",
compute: { compute: {
module: paletteShader.module, module: paletteShader.module,
@@ -137,5 +137,5 @@ export default ({ config, device, timeBuffer }) => {
computePass.end(); computePass.end();
}; };
return makePass(loaded, build, run); return makePass("Palette", loaded, build, run);
}; };

View File

@@ -104,47 +104,49 @@ export default ({ config, device, timeBuffer }) => {
sceneUniforms = rainShaderUniforms.Scene; sceneUniforms = rainShaderUniforms.Scene;
sceneBuffer = makeUniformBuffer(device, sceneUniforms); sceneBuffer = makeUniformBuffer(device, sceneUniforms);
computePipeline = device.createComputePipeline({
layout: "auto",
compute: {
module: rainShader.module,
entryPoint: "computeMain",
},
});
const additiveBlendComponent = { const additiveBlendComponent = {
operation: "add", operation: "add",
srcFactor: "one", srcFactor: "one",
dstFactor: "one", dstFactor: "one",
}; };
renderPipeline = device.createRenderPipeline({ [computePipeline, renderPipeline] = await Promise.all([
layout: "auto", device.createComputePipelineAsync({
vertex: { layout: "auto",
module: rainShader.module, compute: {
entryPoint: "vertMain", module: rainShader.module,
}, entryPoint: "computeMain",
fragment: { },
module: rainShader.module, }),
entryPoint: "fragMain",
targets: [ device.createRenderPipelineAsync({
{ layout: "auto",
format: renderFormat, vertex: {
blend: { module: rainShader.module,
color: additiveBlendComponent, entryPoint: "vertMain",
alpha: additiveBlendComponent, },
fragment: {
module: rainShader.module,
entryPoint: "fragMain",
targets: [
{
format: renderFormat,
blend: {
color: additiveBlendComponent,
alpha: additiveBlendComponent,
},
}, },
}, {
{ format: renderFormat,
format: renderFormat, blend: {
blend: { color: additiveBlendComponent,
color: additiveBlendComponent, alpha: additiveBlendComponent,
alpha: additiveBlendComponent, },
}, },
}, ],
], },
}, }),
}); ]);
computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer]); computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer]);
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [configBuffer, timeBuffer, sceneBuffer, linearSampler, msdfTexture.createView(), cellsBuffer]); renderBindGroup = makeBindGroup(device, renderPipeline, 0, [configBuffer, timeBuffer, sceneBuffer, linearSampler, msdfTexture.createView(), cellsBuffer]);
@@ -196,5 +198,5 @@ export default ({ config, device, timeBuffer }) => {
renderPass.end(); renderPass.end();
}; };
return makePass(loaded, build, run); return makePass("Rain", loaded, build, run);
}; };

View File

@@ -65,7 +65,8 @@ export default ({ config, device, timeBuffer }) => {
const loaded = (async () => { const loaded = (async () => {
const [stripeShader] = await Promise.all(assets); const [stripeShader] = await Promise.all(assets);
computePipeline = device.createComputePipeline({ computePipeline = await device.createComputePipelineAsync({
layout: "auto",
compute: { compute: {
module: stripeShader.module, module: stripeShader.module,
entryPoint: "computeMain", entryPoint: "computeMain",
@@ -110,5 +111,5 @@ export default ({ config, device, timeBuffer }) => {
computePass.end(); computePass.end();
}; };
return makePass(loaded, build, run); return makePass("Stripe", loaded, build, run);
}; };

View File

@@ -1,4 +1,6 @@
/* /*
// TODO: switch back to this impl once it doesn't break on FF Nightly
const loadTexture = async (device, url) => { const loadTexture = async (device, url) => {
const response = await fetch(url); const response = await fetch(url);
const data = await response.blob(); 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(), loaded: loaded ?? Promise.resolve(),
build: build ?? ((size, inputs) => inputs), build: build ?? ((size, inputs) => inputs),
run: run ?? (() => {}), run: (encoder) => {
encoder.pushDebugGroup(`Pass "${name}"`);
run?.(encoder);
encoder.popDebugGroup();
},
}); });
const makePipeline = async (context, steps) => { const makePipeline = async (context, steps) => {