Unifying the interfaces of regl and webgpu makePass and makePipeline.

This commit is contained in:
Rezmason
2021-11-09 09:17:01 -08:00
parent 6586badf42
commit 87c2093281
14 changed files with 55 additions and 68 deletions

View File

@@ -9,7 +9,7 @@ const levelStrengths = Array(pyramidHeight)
.map((_, index) => Math.pow(index / (pyramidHeight * 2) + 0.5, 1 / 3).toPrecision(5))
.reverse();
export default (regl, config, inputs) => {
export default ({ regl, config }, inputs) => {
const { bloomStrength, bloomSize, highPassThreshold } = config;
const enabled = bloomSize > 0 && bloomStrength > 0;
@@ -80,6 +80,14 @@ export default (regl, config, inputs) => {
primary: inputs.primary,
bloom: output,
},
Promise.all([highPassFrag.loaded, blurFrag.loaded]),
(w, h) => {
// The blur pyramids can be lower resolution than the screen.
resizePyramid(highPassPyramid, w, h, bloomSize);
resizePyramid(hBlurPyramid, w, h, bloomSize);
resizePyramid(vBlurPyramid, w, h, bloomSize);
output.resize(w, h);
},
() => {
for (let i = 0; i < pyramidHeight; i++) {
const highPassFBO = highPassPyramid[i];
@@ -91,14 +99,6 @@ export default (regl, config, inputs) => {
}
sumPyramid();
},
(w, h) => {
// The blur pyramids can be lower resolution than the screen.
resizePyramid(highPassPyramid, w, h, bloomSize);
resizePyramid(hBlurPyramid, w, h, bloomSize);
resizePyramid(vBlurPyramid, w, h, bloomSize);
output.resize(w, h);
},
[highPassFrag.loaded, blurFrag.loaded]
}
);
};

View File

@@ -4,7 +4,7 @@ import { loadImage, loadText, makePassFBO, makePass } from "./utils.js";
const defaultBGURL = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flammarion_Colored.jpg/917px-Flammarion_Colored.jpg";
export default (regl, config, inputs) => {
export default ({ regl, config }, inputs) => {
const output = makePassFBO(regl, config.useHalfFloat);
const bgURL = "bgURL" in config ? config.bgURL : defaultBGURL;
const background = loadImage(regl, bgURL);
@@ -22,8 +22,8 @@ export default (regl, config, inputs) => {
{
primary: output,
},
() => render({ frag: imagePassFrag.text() }),
null,
[background.loaded, imagePassFrag.loaded]
Promise.all([background.loaded, imagePassFrag.loaded]),
(w, h) => output.resize(w, h),
() => render({ frag: imagePassFrag.text() })
);
};

View File

@@ -40,7 +40,7 @@ export default async (canvas, config) => {
// All this takes place in a full screen quad.
const fullScreenQuad = makeFullScreenQuad(regl);
const effectName = config.effect in effects ? config.effect : "plain";
const pipeline = makePipeline([makeRain, makeBloomPass, effects[effectName]], (p) => p.outputs, regl, config);
const pipeline = makePipeline({ regl, config }, [makeRain, makeBloomPass, effects[effectName]]);
const screenUniforms = { tex: pipeline[pipeline.length - 1].outputs.primary };
const drawToScreen = regl({ uniforms: screenUniforms });
await Promise.all(pipeline.map((step) => step.ready));
@@ -50,12 +50,12 @@ export default async (canvas, config) => {
dimensions.width = viewportWidth;
dimensions.height = viewportHeight;
for (const step of pipeline) {
step.resize(viewportWidth, viewportHeight);
step.setSize(viewportWidth, viewportHeight);
}
}
fullScreenQuad(() => {
for (const step of pipeline) {
step.render();
step.execute();
}
drawToScreen();
});

View File

@@ -62,7 +62,7 @@ const makePalette = (regl, entries) => {
// won't persist across subsequent frames. This is a safe trick
// in screen space.
export default (regl, config, inputs) => {
export default ({ regl, config }, inputs) => {
const output = makePassFBO(regl, config.useHalfFloat);
const palette = makePalette(regl, config.paletteEntries);
const { backgroundColor } = config;
@@ -86,8 +86,8 @@ export default (regl, config, inputs) => {
{
primary: output,
},
() => render({ frag: palettePassFrag.text() }),
null,
palettePassFrag.loaded
palettePassFrag.loaded,
(w, h) => output.resize(w, h),
() => render({ frag: palettePassFrag.text() })
);
};

View File

@@ -19,7 +19,7 @@ const blVert = [1, 0];
const brVert = [1, 1];
const quadVertices = [tlVert, trVert, brVert, tlVert, brVert, blVert];
export default (regl, config) => {
export default ({ regl, config }) => {
// The volumetric mode multiplies the number of columns
// to reach the desired density, and then overlaps them
const volumetric = config.volumetric;
@@ -170,15 +170,7 @@ export default (regl, config) => {
{
primary: output,
},
() => {
compute({ frag: rainPassCompute.text() });
regl.clear({
depth: 1,
color: [0, 0, 0, 1],
framebuffer: output,
});
render({ camera, transform, screenSize, vert: rainPassVert.text(), frag: rainPassFrag.text() });
},
Promise.all([msdf.loaded, rainPassCompute.loaded, rainPassVert.loaded, rainPassFrag.loaded]),
(w, h) => {
output.resize(w, h);
const aspectRatio = w / h;
@@ -193,6 +185,14 @@ export default (regl, config) => {
}
[screenSize[0], screenSize[1]] = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
},
[msdf.loaded, rainPassCompute.loaded, rainPassVert.loaded, rainPassFrag.loaded]
() => {
compute({ frag: rainPassCompute.text() });
regl.clear({
depth: 1,
color: [0, 0, 0, 1],
framebuffer: output,
});
render({ camera, transform, screenSize, vert: rainPassVert.text(), frag: rainPassFrag.text() });
}
);
};

View File

@@ -8,7 +8,7 @@ import { loadText, make1DTexture, makePassFBO, makePass } from "./utils.js";
// Downward-flowing glyphs should be tinted slightly blue on top and golden on the bottom
// Cheat a lens blur, interpolating between the texture and bloom at the edges
export default (regl, config, inputs) => {
export default ({ regl, config }, inputs) => {
const output = makePassFBO(regl, config.useHalfFloat);
const { backgroundColor } = config;
const resurrectionPassFrag = loadText("shaders/glsl/resurrectionPass.frag.glsl");
@@ -29,8 +29,8 @@ export default (regl, config, inputs) => {
{
primary: output,
},
() => render({ frag: resurrectionPassFrag.text() }),
null,
resurrectionPassFrag.loaded
resurrectionPassFrag.loaded,
(w, h) => output.resize(w, h),
() => render({ frag: resurrectionPassFrag.text() })
);
};

View File

@@ -28,7 +28,7 @@ const prideStripeColors = [
[0.8, 0, 1],
].flat();
export default (regl, config, inputs) => {
export default ({ regl, config }, inputs) => {
const output = makePassFBO(regl, config.useHalfFloat);
const { backgroundColor } = config;
@@ -61,8 +61,8 @@ export default (regl, config, inputs) => {
{
primary: output,
},
() => render({ frag: stripePassFrag.text() }),
null,
stripePassFrag.loaded
stripePassFrag.loaded,
(w, h) => output.resize(w, h),
() => render({ frag: stripePassFrag.text() })
);
};

View File

@@ -129,28 +129,15 @@ const make1DTexture = (regl, data) =>
min: "linear",
});
const makePass = (outputs, render, resize, ready) => {
if (render == null) {
render = () => {};
}
if (resize == null) {
resize = (w, h) => Object.values(outputs).forEach((output) => output.resize(w, h));
}
if (ready == null) {
ready = Promise.resolve();
} else if (ready instanceof Array) {
ready = Promise.all(ready);
}
return {
outputs,
render,
resize,
ready,
};
};
const makePass = (outputs, ready, setSize, execute) => ({
outputs: outputs ?? {},
ready: ready ?? Promise.resolve(),
setSize: setSize ?? (() => {}),
execute: execute ?? (() => {}),
});
const makePipeline = (steps, getInputs, ...params) =>
steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(...params, i == 0 ? null : getInputs(pipeline[i - 1]))], []);
const makePipeline = (context, steps) =>
steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(context, i == 0 ? null : pipeline[i - 1].outputs)], []);
export {
makePassTexture,

View File

@@ -76,5 +76,5 @@ export default (context, getInputs) => {
renderPass.endPass();
};
return makePass(ready, setSize, getOutputs, execute);
return makePass(getOutputs, ready, setSize, execute);
};

View File

@@ -161,5 +161,5 @@ export default (context, getInputs) => {
renderPass.endPass();
};
return makePass(ready, setSize, getOutputs, execute);
return makePass(getOutputs, ready, setSize, execute);
};

View File

@@ -193,5 +193,5 @@ export default (context, getInputs) => {
renderPass.endPass();
};
return makePass(ready, setSize, getOutputs, execute);
return makePass(getOutputs, ready, setSize, execute);
};

View File

@@ -83,5 +83,5 @@ export default (context, getInputs) => {
renderPass.endPass();
};
return makePass(ready, setSize, getOutputs, execute);
return makePass(getOutputs, ready, setSize, execute);
};

View File

@@ -125,5 +125,5 @@ export default (context, getInputs) => {
renderPass.endPass();
};
return makePass(ready, setSize, getOutputs, execute);
return makePass(getOutputs, ready, setSize, execute);
};

View File

@@ -80,10 +80,10 @@ const makeBindGroup = (device, pipeline, index, entries) =>
})),
});
const makePass = (ready, setSize, getOutputs, execute) => ({
const makePass = (getOutputs, ready, setSize, execute) => ({
getOutputs: getOutputs ?? (() => ({})),
ready: ready ?? Promise.resolve(),
setSize: setSize ?? (() => {}),
getOutputs: getOutputs ?? (() => ({})),
execute: execute ?? (() => {}),
});