mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-14 12:29:30 -07:00
Adding an FPS argument. The renderers now determine whether the current frame should be rendered, and passes use that to determine whether to render or not. The rain pass, however, will still update the simulation at full speed.
This commit is contained in:
@@ -135,7 +135,11 @@ export default ({ config, device }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const run = (encoder) => {
|
||||
const run = (encoder, shouldRender) => {
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
const computePass = encoder.beginComputePass();
|
||||
|
||||
computePass.setPipeline(blurPipeline);
|
||||
|
||||
@@ -49,7 +49,11 @@ export default ({ device, canvasFormat, canvasContext }) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const run = (encoder) => {
|
||||
const run = (encoder, shouldRender) => {
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView();
|
||||
const renderPass = encoder.beginRenderPass(renderPassConfig);
|
||||
renderPass.setPipeline(renderPipeline);
|
||||
|
||||
@@ -53,7 +53,11 @@ export default ({ config, device }) => {
|
||||
return { primary: output };
|
||||
};
|
||||
|
||||
const run = (encoder) => {
|
||||
const run = (encoder, shouldRender) => {
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
const computePass = encoder.beginComputePass();
|
||||
computePass.setPipeline(computePipeline);
|
||||
computePass.setBindGroup(0, computeBindGroup);
|
||||
|
||||
@@ -92,8 +92,10 @@ export default async (canvas, config) => {
|
||||
const effectName = config.effect in effects ? config.effect : "palette";
|
||||
const pipeline = await makePipeline(context, [makeRain, makeBloomPass, effects[effectName], makeEndPass]);
|
||||
|
||||
const targetFrameTimeMilliseconds = 1000 / config.fps;
|
||||
let frames = 0;
|
||||
let start = NaN;
|
||||
let last = NaN;
|
||||
let outputs;
|
||||
|
||||
const renderLoop = (now) => {
|
||||
@@ -101,6 +103,17 @@ export default async (canvas, config) => {
|
||||
start = now;
|
||||
}
|
||||
|
||||
if (isNaN(last)) {
|
||||
last = start;
|
||||
}
|
||||
|
||||
const shouldRender = config.fps >= 60 || now - last >= targetFrameTimeMilliseconds || config.once;
|
||||
if (shouldRender) {
|
||||
while (now - targetFrameTimeMilliseconds > last) {
|
||||
last += targetFrameTimeMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
const devicePixelRatio = window.devicePixelRatio ?? 1;
|
||||
const canvasWidth = canvas.clientWidth * devicePixelRatio;
|
||||
const canvasHeight = canvas.clientHeight * devicePixelRatio;
|
||||
@@ -119,10 +132,11 @@ export default async (canvas, config) => {
|
||||
frames++;
|
||||
|
||||
const encoder = device.createCommandEncoder();
|
||||
pipeline.run(encoder);
|
||||
pipeline.run(encoder, shouldRender);
|
||||
// Eventually, when WebGPU allows it, we'll remove the endPass and just copy from our pipeline's output to the canvas texture.
|
||||
// encoder.copyTextureToTexture({ texture: outputs?.primary }, { texture: canvasContext.getCurrentTexture() }, canvasSize);
|
||||
device.queue.submit([encoder.finish()]);
|
||||
|
||||
if (!config.once) {
|
||||
requestAnimationFrame(renderLoop);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,11 @@ export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) =>
|
||||
return { primary: output };
|
||||
};
|
||||
|
||||
const run = (encoder) => {
|
||||
const run = (encoder, shouldRender) => {
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (touchesChanged) {
|
||||
touchesChanged = false;
|
||||
device.queue.writeBuffer(touchBuffer, 0, touchUniforms.toBuffer({ touches }));
|
||||
|
||||
@@ -123,7 +123,11 @@ export default ({ config, device, timeBuffer }) => {
|
||||
return { primary: output };
|
||||
};
|
||||
|
||||
const run = (encoder) => {
|
||||
const run = (encoder, shouldRender) => {
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
const computePass = encoder.beginComputePass();
|
||||
computePass.setPipeline(computePipeline);
|
||||
computePass.setBindGroup(0, computeBindGroup);
|
||||
|
||||
@@ -207,7 +207,7 @@ export default ({ config, device, timeBuffer }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const run = (encoder) => {
|
||||
const run = (encoder, shouldRender) => {
|
||||
// We render the code into an Target using MSDFs: https://github.com/Chlumsky/msdfgen
|
||||
|
||||
const introPass = encoder.beginComputePass();
|
||||
@@ -222,13 +222,15 @@ export default ({ config, device, timeBuffer }) => {
|
||||
computePass.dispatchWorkgroups(Math.ceil(gridSize[0] / 32), gridSize[1], 1);
|
||||
computePass.end();
|
||||
|
||||
renderPassConfig.colorAttachments[0].view = output.createView();
|
||||
renderPassConfig.colorAttachments[1].view = highPassOutput.createView();
|
||||
const renderPass = encoder.beginRenderPass(renderPassConfig);
|
||||
renderPass.setPipeline(renderPipeline);
|
||||
renderPass.setBindGroup(0, renderBindGroup);
|
||||
renderPass.draw(numVerticesPerQuad * numQuads, 1, 0, 0);
|
||||
renderPass.end();
|
||||
if (shouldRender) {
|
||||
renderPassConfig.colorAttachments[0].view = output.createView();
|
||||
renderPassConfig.colorAttachments[1].view = highPassOutput.createView();
|
||||
const renderPass = encoder.beginRenderPass(renderPassConfig);
|
||||
renderPass.setPipeline(renderPipeline);
|
||||
renderPass.setBindGroup(0, renderBindGroup);
|
||||
renderPass.draw(numVerticesPerQuad * numQuads, 1, 0, 0);
|
||||
renderPass.end();
|
||||
}
|
||||
};
|
||||
|
||||
return makePass("Rain", loaded, build, run);
|
||||
|
||||
@@ -92,7 +92,11 @@ export default ({ config, device, timeBuffer }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const run = (encoder) => {
|
||||
const run = (encoder, shouldRender) => {
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
const computePass = encoder.beginComputePass();
|
||||
computePass.setPipeline(computePipeline);
|
||||
const computeBindGroup = makeBindGroup(device, computePipeline, 0, [
|
||||
|
||||
@@ -118,9 +118,9 @@ const makeBindGroup = (device, pipeline, index, entries) =>
|
||||
const makePass = (name, loaded, build, run) => ({
|
||||
loaded: loaded ?? Promise.resolve(),
|
||||
build: build ?? ((size, inputs) => inputs),
|
||||
run: (encoder) => {
|
||||
run: (encoder, shouldRender) => {
|
||||
encoder.pushDebugGroup(`Pass "${name}"`);
|
||||
run?.(encoder);
|
||||
run?.(encoder, shouldRender);
|
||||
encoder.popDebugGroup();
|
||||
},
|
||||
});
|
||||
@@ -131,7 +131,7 @@ const makePipeline = async (context, steps) => {
|
||||
return {
|
||||
steps,
|
||||
build: (canvasSize) => steps.reduce((outputs, step) => step.build(canvasSize, outputs), null),
|
||||
run: (encoder) => steps.forEach((step) => step.run(encoder)),
|
||||
run: (encoder, shouldRender) => steps.forEach((step) => step.run(encoder, shouldRender)),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user