Finding ways to construct WebGPU descriptors more concisely. Moving some functions to webgpu's utils.js.

This commit is contained in:
Rezmason
2021-10-30 08:40:31 -07:00
parent 0c26cc7660
commit 33437a722d
4 changed files with 71 additions and 113 deletions

View File

@@ -17,6 +17,8 @@ WebGPU
The other passes should be a breeze The other passes should be a breeze
Just add them to the render bundle Just add them to the render bundle
Update links in issues
std140 std140
Document and share it Document and share it

View File

@@ -155,12 +155,9 @@ export default (regl, config) => {
// Camera and transform math for the volumetric mode // Camera and transform math for the volumetric mode
const screenSize = [1, 1]; const screenSize = [1, 1];
const { mat4, vec3 } = glMatrix; const { mat4, vec3 } = glMatrix;
const camera = mat4.create();
const translation = vec3.set(vec3.create(), 0, 0, -1);
const scale = vec3.set(vec3.create(), 1, 1, 1);
const transform = mat4.create(); const transform = mat4.create();
mat4.translate(transform, transform, translation); mat4.translate(transform, transform, vec3.fromValues(0, 0, -1));
mat4.scale(transform, transform, scale); const camera = mat4.create();
return makePass( return makePass(
{ {

View File

@@ -1,49 +1,10 @@
import std140 from "./std140.js"; import std140 from "./std140.js";
import { getCanvasSize, loadTexture, makeUniformBuffer } from "./utils.js";
const { mat4, vec3 } = glMatrix; const { mat4, vec3 } = glMatrix;
const getCanvasSize = (canvas) => {
const devicePixelRatio = window.devicePixelRatio ?? 1;
return [canvas.clientWidth * devicePixelRatio, canvas.clientHeight * devicePixelRatio];
};
const loadTexture = async (device, url) => {
const image = new Image();
image.crossOrigin = "anonymous";
image.src = url;
await image.decode();
const imageBitmap = await createImageBitmap(image);
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;
};
export default async (canvas, config) => { export default async (canvas, config) => {
console.log(config); console.log(config);
const NUM_VERTICES_PER_QUAD = 6;
const numColumns = config.numColumns;
const numRows = config.numColumns;
if (navigator.gpu == null) {
return;
}
const adapter = await navigator.gpu.requestAdapter(); const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice(); const device = await adapter.requestDevice();
const canvasContext = canvas.getContext("webgpu"); const canvasContext = canvas.getContext("webgpu");
@@ -68,6 +29,11 @@ export default async (canvas, config) => {
], ],
}; };
const NUM_VERTICES_PER_QUAD = 6;
const numColumns = config.numColumns;
const numRows = config.numColumns;
const msdfSampler = device.createSampler({ const msdfSampler = device.createSampler({
magFilter: "linear", magFilter: "linear",
minFilter: "linear", minFilter: "linear",
@@ -76,42 +42,20 @@ export default async (canvas, config) => {
const msdfTexture = await loadTexture(device, config.glyphTexURL); const msdfTexture = await loadTexture(device, config.glyphTexURL);
const configStructLayout = std140(["i32", "i32", "f32"]); const configStructLayout = std140(["i32", "i32", "f32"]);
const configBufferSize = configStructLayout.size; const configBuffer = makeUniformBuffer(device, configStructLayout, [numColumns, numRows, config.glyphHeightToWidth]);
const configBuffer = device.createBuffer({
size: configBufferSize,
usage: GPUBufferUsage.UNIFORM,
mappedAtCreation: true,
});
configStructLayout.build([numColumns, numRows, config.glyphHeightToWidth], configBuffer.getMappedRange());
configBuffer.unmap();
const msdfStructLayout = std140(["i32", "i32"]); const msdfStructLayout = std140(["i32", "i32"]);
const msdfBuffer = device.createBuffer({ const msdfBuffer = makeUniformBuffer(device, msdfStructLayout, [config.glyphTextureColumns, config.glyphSequenceLength]);
size: msdfStructLayout.size,
usage: GPUBufferUsage.UNIFORM,
mappedAtCreation: true,
});
msdfStructLayout.build([config.glyphTextureColumns, config.glyphSequenceLength], msdfBuffer.getMappedRange());
msdfBuffer.unmap();
const timeStructLayout = std140(["f32", "i32"]); const timeStructLayout = std140(["f32", "i32"]);
const timeBuffer = device.createBuffer({ const timeBuffer = makeUniformBuffer(device, timeStructLayout);
size: timeStructLayout.size,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
const sceneStructLayout = std140(["vec2<f32>", "mat4x4<f32>", "mat4x4<f32>"]); const sceneStructLayout = std140(["vec2<f32>", "mat4x4<f32>", "mat4x4<f32>"]);
const sceneBuffer = device.createBuffer({ const sceneBuffer = makeUniformBuffer(device, sceneStructLayout);
size: sceneStructLayout.size,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
const camera = mat4.create();
const translation = vec3.set(vec3.create(), 0, 0, -1);
const scale = vec3.set(vec3.create(), 1, 1, 1);
const transform = mat4.create(); const transform = mat4.create();
mat4.translate(transform, transform, translation); mat4.translate(transform, transform, vec3.fromValues(0, 0, -1));
mat4.scale(transform, transform, scale); const camera = mat4.create();
const updateCameraBuffer = () => { const updateCameraBuffer = () => {
const canvasSize = canvasConfig.size; const canvasSize = canvasConfig.size;
@@ -132,11 +76,6 @@ export default async (canvas, config) => {
dstFactor: "one", dstFactor: "one",
}; };
const additiveBlending = {
color: additiveBlendComponent,
alpha: additiveBlendComponent,
};
const rainRenderPipeline = device.createRenderPipeline({ const rainRenderPipeline = device.createRenderPipeline({
vertex: { vertex: {
module: rainRenderShaderModule, module: rainRenderShaderModule,
@@ -148,7 +87,10 @@ export default async (canvas, config) => {
targets: [ targets: [
{ {
format: presentationFormat, format: presentationFormat,
blend: additiveBlending, blend: {
color: additiveBlendComponent,
alpha: additiveBlendComponent,
},
}, },
], ],
}, },
@@ -158,40 +100,12 @@ export default async (canvas, config) => {
const bindGroup = device.createBindGroup({ const bindGroup = device.createBindGroup({
layout: rainRenderPipeline.getBindGroupLayout(0), layout: rainRenderPipeline.getBindGroupLayout(0),
entries: [ entries: [configBuffer, msdfBuffer, msdfSampler, msdfTexture.createView(), timeBuffer, sceneBuffer]
{ .map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
binding: 0, .map((resource, binding) => ({
resource: { binding,
buffer: configBuffer, resource,
}, })),
},
{
binding: 1,
resource: {
buffer: msdfBuffer,
},
},
{
binding: 2,
resource: msdfSampler,
},
{
binding: 3,
resource: msdfTexture.createView(),
},
{
binding: 4,
resource: {
buffer: timeBuffer,
},
},
{
binding: 5,
resource: {
buffer: sceneBuffer,
},
},
],
}); });
const bundleEncoder = device.createRenderBundleEncoder({ const bundleEncoder = device.createRenderBundleEncoder({

45
js/webgpu/utils.js Normal file
View File

@@ -0,0 +1,45 @@
const getCanvasSize = (canvas) => {
const devicePixelRatio = window.devicePixelRatio ?? 1;
return [canvas.clientWidth * devicePixelRatio, canvas.clientHeight * devicePixelRatio];
};
const loadTexture = async (device, url) => {
const image = new Image();
image.crossOrigin = "anonymous";
image.src = url;
await image.decode();
const imageBitmap = await createImageBitmap(image);
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 makeUniformBuffer = (device, structLayout, values = null) => {
const buffer = device.createBuffer({
size: structLayout.size,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
mappedAtCreation: values != null,
});
if (values != null) {
structLayout.build(values, buffer.getMappedRange());
buffer.unmap();
}
return buffer;
};
export { getCanvasSize, loadTexture, makeUniformBuffer };