The MSDF stuff shouldn't be in its own uniform buffer. This is basically config stuff.

Added a compute pass that currently does nothing while I learn how to make use of it.
This commit is contained in:
Rezmason
2021-10-31 20:00:11 -07:00
parent 53e1c5502c
commit 6f58882851
3 changed files with 58 additions and 31 deletions

View File

@@ -4,8 +4,11 @@ WebGPU
First decent rainRender First decent rainRender
Port compute pass 100% Port compute pass 100%
Compute entry point can live in the same wgsl file, I think Compute entry point can live in the same wgsl file, I think
use textureLoad for texel access in render pipeline ping-pong buffers
Bind both ping-pong buffers in render pass
The frame integer can be used by the render code to reference the correct one
Reorder the config fields Reorder the config fields
Reconsider how the bind groups are organized?
Render target Render target
Resize accordingly Resize accordingly
Put in its own module Put in its own module
@@ -13,6 +16,7 @@ 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 Update links in issues
std140 std140

View File

@@ -53,6 +53,8 @@ export default async (canvas, config) => {
const configData = [ const configData = [
// common // common
{ name: "animationSpeed", type: "f32", value: config.animationSpeed }, { name: "animationSpeed", type: "f32", value: config.animationSpeed },
{ name: "glyphSequenceLength", type: "i32", value: config.glyphSequenceLength },
{ name: "glyphTextureColumns", type: "i32", value: config.glyphTextureColumns },
{ name: "glyphHeightToWidth", type: "f32", value: config.glyphHeightToWidth }, { name: "glyphHeightToWidth", type: "f32", value: config.glyphHeightToWidth },
{ name: "resurrectingCodeRatio", type: "f32", value: config.resurrectingCodeRatio }, { name: "resurrectingCodeRatio", type: "f32", value: config.resurrectingCodeRatio },
{ name: "gridSize", type: "vec2<f32>", value: gridSize }, { name: "gridSize", type: "vec2<f32>", value: gridSize },
@@ -94,19 +96,6 @@ export default async (canvas, config) => {
configData.map((field) => field.value) configData.map((field) => field.value)
); );
const msdfData = [
{ name: "glyphSequenceLength", type: "i32", value: config.glyphSequenceLength },
{ name: "glyphTextureColumns", type: "i32", value: config.glyphTextureColumns },
];
console.table(msdfData);
const msdfLayout = std140(msdfData.map((field) => field.type));
const msdfBuffer = makeUniformBuffer(
device,
msdfLayout,
msdfData.map((field) => field.value)
);
const timeLayout = std140(["f32", "i32"]); const timeLayout = std140(["f32", "i32"]);
const timeBuffer = makeUniformBuffer(device, timeLayout); const timeBuffer = makeUniformBuffer(device, timeLayout);
@@ -135,6 +124,13 @@ export default async (canvas, config) => {
const rainRenderShaderModule = device.createShaderModule({ code: rainRenderShader }); const rainRenderShaderModule = device.createShaderModule({ code: rainRenderShader });
const rainComputePipeline = device.createComputePipeline({
compute: {
module: rainRenderShaderModule,
entryPoint: "computeMain",
},
});
const additiveBlendComponent = { const additiveBlendComponent = {
operation: "add", operation: "add",
srcFactor: "one", srcFactor: "one",
@@ -161,9 +157,19 @@ export default async (canvas, config) => {
}, },
}); });
const bindGroup = device.createBindGroup({ const renderBindGroup = device.createBindGroup({
layout: rainRenderPipeline.getBindGroupLayout(0), layout: rainRenderPipeline.getBindGroupLayout(0),
entries: [configBuffer, msdfBuffer, msdfSampler, msdfTexture.createView(), timeBuffer, sceneBuffer] entries: [configBuffer, timeBuffer, sceneBuffer, msdfSampler, msdfTexture.createView()]
.map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
.map((resource, binding) => ({
binding,
resource,
})),
});
const computeBindGroup = device.createBindGroup({
layout: rainComputePipeline.getBindGroupLayout(0),
entries: [configBuffer, timeBuffer]
.map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource)) .map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
.map((resource, binding) => ({ .map((resource, binding) => ({
binding, binding,
@@ -176,7 +182,7 @@ export default async (canvas, config) => {
}); });
bundleEncoder.setPipeline(rainRenderPipeline); bundleEncoder.setPipeline(rainRenderPipeline);
bundleEncoder.setBindGroup(0, bindGroup); bundleEncoder.setBindGroup(0, renderBindGroup);
bundleEncoder.draw(numVerticesPerQuad * numQuads, 1, 0, 0); bundleEncoder.draw(numVerticesPerQuad * numQuads, 1, 0, 0);
const renderBundles = [bundleEncoder.finish()]; const renderBundles = [bundleEncoder.finish()];
@@ -209,6 +215,13 @@ export default async (canvas, config) => {
renderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView(); renderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView();
const encoder = device.createCommandEncoder(); const encoder = device.createCommandEncoder();
const computePass = encoder.beginComputePass();
computePass.setPipeline(rainComputePipeline);
computePass.setBindGroup(0, computeBindGroup);
computePass.dispatch(...gridSize, 1);
computePass.endPass();
const renderPass = encoder.beginRenderPass(renderPassConfig); const renderPass = encoder.beginRenderPass(renderPassConfig);
renderPass.executeBundles(renderBundles); renderPass.executeBundles(renderBundles);
renderPass.endPass(); renderPass.endPass();

View File

@@ -9,6 +9,8 @@ let SQRT_5 : f32 = 2.23606797749979;
[[block]] struct Config { [[block]] struct Config {
// common // common
animationSpeed : f32; animationSpeed : f32;
glyphSequenceLength : i32;
glyphTextureColumns : i32;
glyphHeightToWidth : f32; glyphHeightToWidth : f32;
resurrectingCodeRatio : f32; resurrectingCodeRatio : f32;
gridSize : vec2<f32>; gridSize : vec2<f32>;
@@ -43,29 +45,30 @@ let SQRT_5 : f32 = 2.23606797749979;
}; };
[[group(0), binding(0)]] var<uniform> config : Config; [[group(0), binding(0)]] var<uniform> config : Config;
[[block]] struct MSDF {
glyphSequenceLength : i32;
glyphTextureColumns : i32;
};
[[group(0), binding(1)]] var<uniform> msdf : MSDF;
[[group(0), binding(2)]] var msdfSampler : sampler;
[[group(0), binding(3)]] var msdfTexture : texture_2d<f32>;
[[block]] struct Time { [[block]] struct Time {
seconds : f32; seconds : f32;
frames : i32; frames : i32;
}; };
[[group(0), binding(4)]] var<uniform> time : Time; [[group(0), binding(1)]] var<uniform> time : Time;
[[block]] struct Scene { [[block]] struct Scene {
screenSize : vec2<f32>; screenSize : vec2<f32>;
camera : mat4x4<f32>; camera : mat4x4<f32>;
transform : mat4x4<f32>; transform : mat4x4<f32>;
}; };
[[group(0), binding(5)]] var<uniform> scene : Scene; [[group(0), binding(2)]] var<uniform> scene : Scene;
[[group(0), binding(3)]] var msdfSampler : sampler;
[[group(0), binding(4)]] var msdfTexture : texture_2d<f32>;
// Shader params // Shader params
struct ComputeInput {
[[builtin(global_invocation_id)]] id : vec3<u32>;
};
struct VertInput { struct VertInput {
[[builtin(vertex_index)]] index : u32; [[builtin(vertex_index)]] index : u32;
}; };
@@ -100,6 +103,13 @@ fn wobble(x : f32) -> f32 {
return x + 0.3 * sin(SQRT_2 * x) + 0.2 * sin(SQRT_5 * x); return x + 0.3 * sin(SQRT_2 * x) + 0.2 * sin(SQRT_5 * x);
} }
// Compute shader
[[stage(compute), workgroup_size(1, 1, 1)]] fn computeMain(input : ComputeInput) {
var hasSun = bool(config.hasSun); // TODO: remove
var seconds = time.seconds; // TODO: remove
}
// Vertex shader // Vertex shader
[[stage(vertex)]] fn vertMain(input : VertInput) -> VertOutput { [[stage(vertex)]] fn vertMain(input : VertInput) -> VertOutput {
@@ -179,9 +189,9 @@ fn median3(i : vec3<f32>) -> f32 {
} }
fn getSymbolUV(glyphCycle : f32) -> vec2<f32> { fn getSymbolUV(glyphCycle : f32) -> vec2<f32> {
var symbol = i32(f32(msdf.glyphSequenceLength) * glyphCycle); var symbol = i32(f32(config.glyphSequenceLength) * glyphCycle);
var symbolX = symbol % msdf.glyphTextureColumns; var symbolX = symbol % config.glyphTextureColumns;
var symbolY = symbol / msdf.glyphTextureColumns; var symbolY = symbol / config.glyphTextureColumns;
return vec2<f32>(f32(symbolX), f32(symbolY)); return vec2<f32>(f32(symbolX), f32(symbolY));
} }
@@ -233,7 +243,7 @@ fn getSymbolUV(glyphCycle : f32) -> vec2<f32> {
glyphUV = glyphUV - 0.5; glyphUV = glyphUV - 0.5;
glyphUV = glyphUV * clamp(1.0 - config.glyphEdgeCrop, 0.0, 1.0); glyphUV = glyphUV * clamp(1.0 - config.glyphEdgeCrop, 0.0, 1.0);
glyphUV = glyphUV + 0.5; glyphUV = glyphUV + 0.5;
var msdfUV = (glyphUV + symbolUV) / f32(msdf.glyphTextureColumns); var msdfUV = (glyphUV + symbolUV) / f32(config.glyphTextureColumns);
// MSDF : calculate brightness of fragment based on distance to shape // MSDF : calculate brightness of fragment based on distance to shape
var dist = textureSample(msdfTexture, msdfSampler, msdfUV).rgb; var dist = textureSample(msdfTexture, msdfSampler, msdfUV).rgb;