Files
matrix/js/webgpu/utils.js

94 lines
2.7 KiB
JavaScript

const getCanvasSize = (canvas) => {
const devicePixelRatio = window.devicePixelRatio ?? 1;
return [canvas.clientWidth * devicePixelRatio, canvas.clientHeight * devicePixelRatio];
};
const loadTexture = async (device, url) => {
const response = await fetch(url);
const data = await response.blob();
const imageBitmap = await createImageBitmap(data);
const texture = device.createTexture({
size: [imageBitmap.width, imageBitmap.height, 1],
format: "rgba8unorm",
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
device.queue.copyExternalImageToTexture(
{
source: imageBitmap,
},
{
texture: texture,
},
[imageBitmap.width, imageBitmap.height]
);
return texture;
};
const makePassFBO = (device, width, height, format = "bgra8unorm") =>
device.createTexture({
size: [width, height, 1],
format,
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
const loadShader = async (device, url) => {
const response = await fetch(url);
const code = await response.text();
return {
code,
module: device.createShaderModule({ code }),
};
};
const makeUniformBuffer = (device, uniforms, data = null) => {
const buffer = device.createBuffer({
size: uniforms.minSize,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
mappedAtCreation: data != null,
});
if (data != null) {
uniforms.toBuffer(data, buffer.getMappedRange());
buffer.unmap();
}
return buffer;
};
const make1DTexture = (device, rgbas) => {
const size = [rgbas.length];
const texture = device.createTexture({
size,
// dimension: "1d",
format: "rgba8unorm",
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
});
const data = new Uint8ClampedArray(rgbas.map((color) => color.map((f) => f * 0xff)).flat());
device.queue.writeTexture({ texture }, data, {}, size);
return texture;
};
const makeBindGroup = (device, pipeline, index, entries) =>
device.createBindGroup({
layout: pipeline.getBindGroupLayout(index),
entries: entries
.map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
.map((resource, binding) => ({
binding,
resource,
})),
});
const makePass = (getOutputs, ready, setSize, execute) => ({
getOutputs: getOutputs ?? (() => ({})),
ready: ready ?? Promise.resolve(),
setSize: setSize ?? (() => {}),
execute: execute ?? (() => {}),
});
const makePipeline = (context, steps) =>
steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(context, i == 0 ? null : pipeline[i - 1].getOutputs)], []);
export { getCanvasSize, makePassFBO, make1DTexture, loadTexture, loadShader, makeUniformBuffer, makePass, makePipeline, makeBindGroup };