From 8c6214688450af886f21cd358defe2cac883283d Mon Sep 17 00:00:00 2001 From: Rezmason Date: Wed, 27 Oct 2021 01:35:23 -0700 Subject: [PATCH] Fetching WebGPU shaders. Created my first bona fide pipeline. The vertex shader compares the built-in vertex index and the numRows/numColumns uniforms to produce a grid of quads with no vertex or index buffer whatsoever! --- js/webgpu_main.js | 75 ++++++++++++++++++++++++++++++++++++-- shaders/rainPass.frag.wgsl | 3 ++ shaders/rainPass.vert.wgsl | 39 ++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 shaders/rainPass.frag.wgsl create mode 100644 shaders/rainPass.vert.wgsl diff --git a/js/webgpu_main.js b/js/webgpu_main.js index b6d3122..f555f2c 100644 --- a/js/webgpu_main.js +++ b/js/webgpu_main.js @@ -6,6 +6,9 @@ const getCanvasSize = (canvas) => { export default async (canvas, config) => { console.log(config); + const numColumns = config.numColumns; + const numRows = config.numColumns; + if (navigator.gpu == null) { return; } @@ -36,14 +39,78 @@ export default async (canvas, config) => { // TODO: create buffers, uniforms, textures, samplers + const uniformBufferSize = 4 * (1 + 1); + const uniformBuffer = device.createBuffer({ + size: uniformBufferSize, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, // Which of these are necessary? + mappedAtCreation: true, + }); + new Int32Array(uniformBuffer.getMappedRange()).set([numColumns, numRows]); + uniformBuffer.unmap(); + // TODO: create pipelines, bind groups, shaders + const [vert, frag] = await Promise.all(["shaders/rainPass.vert.wgsl", "shaders/rainPass.frag.wgsl"].map(async (path) => (await fetch(path)).text())); + + const additiveBlendComponent = { + operation: "add", + srcFactor: "one", + dstFactor: "one", + }; + + const additiveBlending = { + color: additiveBlendComponent, + alpha: additiveBlendComponent, + }; + + const rainRenderPipeline = device.createRenderPipeline({ + vertex: { + module: device.createShaderModule({ + code: vert, + }), + entryPoint: "main", + }, + fragment: { + module: device.createShaderModule({ + code: frag, + }), + entryPoint: "main", + targets: [ + { + format: presentationFormat, + blend: additiveBlending, + }, + ], + }, + primitive: { + // What happens if this isn't here? + topology: "triangle-list", // What happens if this isn't here? + cullMode: "none", // What happens if this isn't here? + }, + }); + + const uniformBindGroup = device.createBindGroup({ + layout: rainRenderPipeline.getBindGroupLayout(0), + entries: [ + { + binding: 0, + resource: { + buffer: uniformBuffer, + }, + }, + ], + }); + const bundleEncoder = device.createRenderBundleEncoder({ colorFormats: [presentationFormat], }); - // TODO: create render bundle(s) - const bundle = bundleEncoder.finish(); - const renderBundles = [bundle]; + + bundleEncoder.setPipeline(rainRenderPipeline); + bundleEncoder.setBindGroup(0, uniformBindGroup); + bundleEncoder.draw(6 * numColumns * numRows, 1, 0, 0); + const renderBundles = [bundleEncoder.finish()]; + + // queue.writeBuffer(uniformBuffer, 0, new Int32Array([numColumns, numRows])); const frame = (now) => { const canvasSize = getCanvasSize(canvas); @@ -58,7 +125,7 @@ export default async (canvas, config) => { // TODO: update the uniforms that change, write to queue - renderPassConfig.colorAttachments[0].loadValue.g = Math.sin((now / 1000) * 2) / 2 + 0.5; + renderPassConfig.colorAttachments[0].loadValue.r = Math.sin((now / 1000) * 2) / 2 + 0.5; renderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView(); const encoder = device.createCommandEncoder(); diff --git a/shaders/rainPass.frag.wgsl b/shaders/rainPass.frag.wgsl new file mode 100644 index 0000000..f9b3092 --- /dev/null +++ b/shaders/rainPass.frag.wgsl @@ -0,0 +1,3 @@ +[[stage(fragment)]] fn main([[location(0)]] UV : vec2) -> [[location(0)]] vec4 { + return vec4(0.0, UV, 1.0); +} diff --git a/shaders/rainPass.vert.wgsl b/shaders/rainPass.vert.wgsl new file mode 100644 index 0000000..a589d2f --- /dev/null +++ b/shaders/rainPass.vert.wgsl @@ -0,0 +1,39 @@ +[[block]] struct Uniforms { + numColumns: i32; + numRows: i32; +}; +[[binding(0), group(0)]] var uniforms : Uniforms; + +struct VertexOutput { + [[builtin(position)]] Position : vec4; + [[location(0)]] UV : vec2; +}; + +[[stage(vertex)]] fn main([[builtin(vertex_index)]] VertexIndex : u32) -> VertexOutput { + + var i = i32(VertexIndex); + var quadIndex = i / 6; + + var cornerPosition = vec2( + f32(i % 2), + f32(((i + 1) % 6 / 3)) + ); + + var x = uniforms.numColumns; + + var position = cornerPosition; + position = position + vec2( + f32(quadIndex % uniforms.numColumns), + f32(quadIndex / uniforms.numColumns) + ); + position = position / vec2( + f32(uniforms.numColumns), + f32(uniforms.numRows) + ); + position = position * 2.0 - 1.0; + + return VertexOutput( + vec4(position, 1.0, 1.0), + cornerPosition + ); +}