From f8959cd7d93819b639c5098ff6ee69d7d25f27dc Mon Sep 17 00:00:00 2001 From: Rezmason Date: Wed, 3 Nov 2021 20:01:59 -0700 Subject: [PATCH] Renaming msdfSampler to linearSampler; adding loadShaderModule utility method; busting the rain render out of its render bundle (which won't be useful long-term). --- TODO.txt | 2 +- js/webgpu/main.js | 28 ++++++++++------------------ js/webgpu/utils.js | 8 +++++++- shaders/wgsl/rainPass.wgsl | 4 ++-- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/TODO.txt b/TODO.txt index 30c657b..a622f38 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,8 +4,8 @@ WebGPU Render targets Resize accordingly Blur: compute or render? + What is workgroupBarrier in compute shaders? The other passes should be a breeze - Just add them to the render bundle Make sure you got CORS right in the texture fetch Update links in issues diff --git a/js/webgpu/main.js b/js/webgpu/main.js index a9969a3..09d8ab9 100644 --- a/js/webgpu/main.js +++ b/js/webgpu/main.js @@ -1,5 +1,6 @@ import std140 from "./std140.js"; -import { getCanvasSize, loadTexture, makeUniformBuffer } from "./utils.js"; +import { getCanvasSize, loadTexture, loadShaderModule, makeUniformBuffer } from "./utils.js"; + const { mat4, vec3 } = glMatrix; const rippleTypes = { @@ -30,8 +31,7 @@ export default async (canvas, config) => { canvasContext.configure(canvasConfig); - const msdfTexturePromise = loadTexture(device, config.glyphTexURL); - const rainShaderPromise = fetch("shaders/wgsl/rainPass.wgsl").then((response) => response.text()); + const assets = [loadTexture(device, config.glyphTexURL), loadShaderModule(device, "shaders/wgsl/rainPass.wgsl")]; // The volumetric mode multiplies the number of columns // to reach the desired density, and then overlaps them @@ -121,14 +121,12 @@ export default async (canvas, config) => { }; updateCameraBuffer(); - const msdfSampler = device.createSampler({ + const linearSampler = device.createSampler({ magFilter: "linear", minFilter: "linear", }); - const [msdfTexture, rainShader] = await Promise.all([msdfTexturePromise, rainShaderPromise]); - - const rainShaderModule = device.createShaderModule({ code: rainShader }); + const [msdfTexture, rainShaderModule] = await Promise.all(assets); const rainComputePipeline = device.createComputePipeline({ compute: { @@ -175,7 +173,7 @@ export default async (canvas, config) => { const renderBindGroup = device.createBindGroup({ layout: rainRenderPipeline.getBindGroupLayout(0), - entries: [configBuffer, timeBuffer, sceneBuffer, msdfSampler, msdfTexture.createView(), cellsBuffer] + entries: [configBuffer, timeBuffer, sceneBuffer, linearSampler, msdfTexture.createView(), cellsBuffer] .map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource)) .map((resource, binding) => ({ binding, @@ -183,15 +181,6 @@ export default async (canvas, config) => { })), }); - const bundleEncoder = device.createRenderBundleEncoder({ - colorFormats: [presentationFormat], - }); - - bundleEncoder.setPipeline(rainRenderPipeline); - bundleEncoder.setBindGroup(0, renderBindGroup); - bundleEncoder.draw(numVerticesPerQuad * numQuads, 1, 0, 0); - const renderBundles = [bundleEncoder.finish()]; - const renderPassConfig = { colorAttachments: [ { @@ -228,8 +217,11 @@ export default async (canvas, config) => { renderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView(); const renderPass = encoder.beginRenderPass(renderPassConfig); - renderPass.executeBundles(renderBundles); + renderPass.setPipeline(rainRenderPipeline); + renderPass.setBindGroup(0, renderBindGroup); + renderPass.draw(numVerticesPerQuad * numQuads, 1, 0, 0); renderPass.endPass(); + const commandBuffer = encoder.finish(); device.queue.submit([commandBuffer]); diff --git a/js/webgpu/utils.js b/js/webgpu/utils.js index 884c0df..eeffeb5 100644 --- a/js/webgpu/utils.js +++ b/js/webgpu/utils.js @@ -27,6 +27,12 @@ const loadTexture = async (device, url) => { return texture; }; +const loadShaderModule = async (device, url) => { + const response = await fetch(url); + const code = await response.text(); + return device.createShaderModule({ code }); +}; + const makeUniformBuffer = (device, structLayout, values = null) => { const buffer = device.createBuffer({ size: structLayout.size, @@ -40,4 +46,4 @@ const makeUniformBuffer = (device, structLayout, values = null) => { return buffer; }; -export { getCanvasSize, loadTexture, makeUniformBuffer }; +export { getCanvasSize, loadTexture, loadShaderModule, makeUniformBuffer }; diff --git a/shaders/wgsl/rainPass.wgsl b/shaders/wgsl/rainPass.wgsl index 35f4c25..a7b1267 100644 --- a/shaders/wgsl/rainPass.wgsl +++ b/shaders/wgsl/rainPass.wgsl @@ -60,7 +60,7 @@ // Render bindings [[group(0), binding(2)]] var scene : Scene; -[[group(0), binding(3)]] var msdfSampler : sampler; +[[group(0), binding(3)]] var linearSampler : sampler; [[group(0), binding(4)]] var msdfTexture : texture_2d; [[group(0), binding(5)]] var cells_RO : CellData; @@ -416,7 +416,7 @@ fn getSymbolUV(glyphCycle : f32) -> vec2 { var msdfUV = (glyphUV + symbolUV) / f32(config.glyphTextureColumns); // MSDF : calculate brightness of fragment based on distance to shape - var dist = textureSample(msdfTexture, msdfSampler, msdfUV).rgb; + var dist = textureSample(msdfTexture, linearSampler, msdfUV).rgb; var sigDist = median3(dist) - 0.5; var alpha = clamp(sigDist / fwidth(sigDist) + 0.5, 0.0, 1.0);