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:
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
Toggle (or number representing frequency)
Load the sound effect
@@ -25,17 +39,6 @@ Support Resurrections SDF bevel and "lights"
Anomaly mode toggles between this and anomaly streaks
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
Get rid of end pass once it's possible to copy a bgra8unorm to a canvas texture
Switch to rgba32float somehow?

View File

@@ -83,8 +83,10 @@ export default ({ config, device, timeBuffer }) => {
let configBuffer;
let sceneUniforms;
let sceneBuffer;
let introPipeline;
let computePipeline;
let renderPipeline;
let introBindGroup;
let computeBindGroup;
let renderBindGroup;
let output;
@@ -115,7 +117,15 @@ export default ({ config, device, timeBuffer }) => {
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({
layout: "auto",
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]);
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [
configBuffer,
@@ -198,6 +209,12 @@ export default ({ config, device, timeBuffer }) => {
const run = (encoder) => {
// 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();
computePass.setPipeline(computePipeline);
computePass.setBindGroup(0, computeBindGroup);

View File

@@ -84,9 +84,12 @@ struct IntroCellData {
@group(0) @binding(0) var<uniform> config : Config;
@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
@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
@group(0) @binding(2) var<uniform> scene : Scene;
@@ -216,7 +219,7 @@ fn getRipple(simTime : f32, screenPos : vec2<f32>) -> f32 {
// 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)) {
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;
}
@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) {
// 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 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 introCell = introCells_RO.cells[column];
cell.raindrop = computeRaindrop(simTime, isFirstFrame, glyphPos, screenPos, cell.raindrop, introCell.progress);
cell.symbol = computeSymbol(simTime, isFirstFrame, glyphPos, screenPos, cell.symbol, cell.raindrop);
cell.effect = computeEffect(simTime, isFirstFrame, glyphPos, screenPos, cell.effect, cell.raindrop);