Fixed a WebGPU sequencing issue when skipIntro=true&once=false, caused by updating the cells and intro cells in the same compute pass. The WebGPU and REGL projects are now also slightly more alike.

This commit is contained in:
Rezmason
2022-09-25 19:22:35 -07:00
parent d3c2773f4f
commit beb70473aa
3 changed files with 59 additions and 21 deletions

View File

@@ -1,5 +1,19 @@
TODO: TODO:
Bloom comparison: WebGPU vs REGL
Why are they different?
Create a project that tests them side-by-side
That's right, two canvases, one regl and one webgpu
program them both to do the same basic ops in a floating point texture
display that texture
Retrieve the texture from the GPU and spit it out
Possible causes of difference
Color space
Intermediate texture formats around high pass filter
Floating point math
Texture interpolation
Blur implementation
Audio system Audio system
Toggle (or number representing frequency) Toggle (or number representing frequency)
Load the sound effect Load the sound effect
@@ -25,17 +39,6 @@ Support Resurrections SDF bevel and "lights"
Anomaly mode toggles between this and anomaly streaks Anomaly mode toggles between this and anomaly streaks
WebGPU WebGPU
Why is it brighter than the regl version?
Create a project that tests them side-by-side
That's right, two canvases, one regl and one webgpu
program them both to do the same basic ops in a floating point texture
display that texture
Retrieve the texture from the GPU and spit it out
Possible causes of difference
Color space
Floating point math
Texture interpolation
Blur implementation
Try https://github.com/brendan-duncan/wgsl_reflect Try https://github.com/brendan-duncan/wgsl_reflect
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?

View File

@@ -83,8 +83,10 @@ export default ({ config, device, timeBuffer }) => {
let configBuffer; let configBuffer;
let sceneUniforms; let sceneUniforms;
let sceneBuffer; let sceneBuffer;
let introPipeline;
let computePipeline; let computePipeline;
let renderPipeline; let renderPipeline;
let introBindGroup;
let computeBindGroup; let computeBindGroup;
let renderBindGroup; let renderBindGroup;
let output; let output;
@@ -115,7 +117,15 @@ export default ({ config, device, timeBuffer }) => {
dstFactor: "one", dstFactor: "one",
}; };
[computePipeline, renderPipeline] = await Promise.all([ [introPipeline, computePipeline, renderPipeline] = await Promise.all([
device.createComputePipelineAsync({
layout: "auto",
compute: {
module: rainShader.module,
entryPoint: "computeIntro",
},
}),
device.createComputePipelineAsync({ device.createComputePipelineAsync({
layout: "auto", layout: "auto",
compute: { compute: {
@@ -153,6 +163,7 @@ export default ({ config, device, timeBuffer }) => {
}), }),
]); ]);
introBindGroup = makeBindGroup(device, introPipeline, 0, [configBuffer, timeBuffer, introCellsBuffer]);
computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer, introCellsBuffer]); computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer, introCellsBuffer]);
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [ renderBindGroup = makeBindGroup(device, renderPipeline, 0, [
configBuffer, configBuffer,
@@ -198,6 +209,12 @@ export default ({ config, device, timeBuffer }) => {
const run = (encoder) => { const run = (encoder) => {
// We render the code into an Target using MSDFs: https://github.com/Chlumsky/msdfgen // We render the code into an Target using MSDFs: https://github.com/Chlumsky/msdfgen
const introPass = encoder.beginComputePass();
introPass.setPipeline(introPipeline);
introPass.setBindGroup(0, introBindGroup);
introPass.dispatchWorkgroups(Math.ceil(gridSize[0] / 32), 1, 1);
introPass.end();
const computePass = encoder.beginComputePass(); const computePass = encoder.beginComputePass();
computePass.setPipeline(computePipeline); computePass.setPipeline(computePipeline);
computePass.setBindGroup(0, computeBindGroup); computePass.setBindGroup(0, computeBindGroup);

View File

@@ -84,9 +84,12 @@ struct IntroCellData {
@group(0) @binding(0) var<uniform> config : Config; @group(0) @binding(0) var<uniform> config : Config;
@group(0) @binding(1) var<uniform> time : Time; @group(0) @binding(1) var<uniform> time : Time;
// Intro-specific bindings
@group(0) @binding(2) var<storage, read_write> introCells_RW : IntroCellData;
// Compute-specific bindings // Compute-specific bindings
@group(0) @binding(2) var<storage, read_write> cells_RW : CellData; @group(0) @binding(2) var<storage, read_write> cells_RW : CellData;
@group(0) @binding(3) var<storage, read_write> introCells_RW : IntroCellData; @group(0) @binding(3) var<storage, read_write> introCells_RO : IntroCellData;
// Render-specific bindings // Render-specific bindings
@group(0) @binding(2) var<uniform> scene : Scene; @group(0) @binding(2) var<uniform> scene : Scene;
@@ -216,7 +219,7 @@ fn getRipple(simTime : f32, screenPos : vec2<f32>) -> f32 {
// Compute shader main functions // Compute shader main functions
fn computeIntro (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, screenPos : vec2<f32>, previous : vec4<f32>) -> vec4<f32> { fn computeIntroProgress (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, screenPos : vec2<f32>, previous : vec4<f32>) -> vec4<f32> {
if (bool(config.skipIntro)) { if (bool(config.skipIntro)) {
return vec4<f32>(2.0, 0.0, 0.0, 0.0); return vec4<f32>(2.0, 0.0, 0.0, 0.0);
} }
@@ -298,6 +301,27 @@ fn computeEffect (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scre
return result; return result;
} }
@compute @workgroup_size(32, 1, 1) fn computeIntro(input : ComputeInput) {
// Resolve the invocation ID to an intro cell coordinate
var column = i32(input.id.x);
if (column >= i32(config.gridSize.x)) {
return;
}
var simTime = time.seconds * config.animationSpeed;
var isFirstFrame = time.frames == 0;
// Update the cell
var glyphPos = vec2<f32>(f32(column), 0.0);
var screenPos = glyphPos / config.gridSize;
var introCell = introCells_RW.cells[column];
introCell.progress = computeIntroProgress(simTime, isFirstFrame, glyphPos, screenPos, introCell.progress);
introCells_RW.cells[column] = introCell;
}
@compute @workgroup_size(32, 1, 1) fn computeMain(input : ComputeInput) { @compute @workgroup_size(32, 1, 1) fn computeMain(input : ComputeInput) {
// Resolve the invocation ID to a cell coordinate // Resolve the invocation ID to a cell coordinate
@@ -317,14 +341,8 @@ fn computeEffect (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scre
var glyphPos = vec2<f32>(f32(column), f32(row)); var glyphPos = vec2<f32>(f32(column), f32(row));
var screenPos = glyphPos / config.gridSize; var screenPos = glyphPos / config.gridSize;
var introCell = introCells_RW.cells[column];
if (row == i32(config.gridSize.y - 1)) {
introCell.progress = computeIntro(simTime, isFirstFrame, glyphPos, screenPos, introCell.progress);
introCells_RW.cells[column] = introCell;
}
var cell = cells_RW.cells[i]; var cell = cells_RW.cells[i];
var introCell = introCells_RO.cells[column];
cell.raindrop = computeRaindrop(simTime, isFirstFrame, glyphPos, screenPos, cell.raindrop, introCell.progress); cell.raindrop = computeRaindrop(simTime, isFirstFrame, glyphPos, screenPos, cell.raindrop, introCell.progress);
cell.symbol = computeSymbol(simTime, isFirstFrame, glyphPos, screenPos, cell.symbol, cell.raindrop); cell.symbol = computeSymbol(simTime, isFirstFrame, glyphPos, screenPos, cell.symbol, cell.raindrop);
cell.effect = computeEffect(simTime, isFirstFrame, glyphPos, screenPos, cell.effect, cell.raindrop); cell.effect = computeEffect(simTime, isFirstFrame, glyphPos, screenPos, cell.effect, cell.raindrop);