From 1a07df64cab20468a9fbfec556d66fa5e15b74aa Mon Sep 17 00:00:00 2001
From: Noratrieb <48135649+Noratrieb@users.noreply.github.com>
Date: Wed, 30 Oct 2024 20:12:31 +0100
Subject: [PATCH] compute
---
index.html | 45 ++++++++++++++++++
index.js | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
mandelbrot.wgsl | 19 ++++++++
shell.nix | 7 +++
4 files changed, 192 insertions(+)
create mode 100644 index.html
create mode 100644 index.js
create mode 100644 mandelbrot.wgsl
create mode 100644 shell.nix
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..bd3a7b0
--- /dev/null
+++ b/index.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+ WebGPU Mandelbrot
+
+
+
+
+
You are using an unsupported browser.
+
+ WebGPU is still experimental and does not have wide browser support.
+
+
+ Check out caniuse.com/webgpu to
+ see which browsers support it.
+
+
+ I recommend using Chrome, which has working implementation on stable at
+ the time of writing. Firefox may have one at the time of reading, in
+ which case I recommend it instead.
+
+
Also check out the Chrome Dev guide when using Chrome
+
+
+ This website uses WebGPU, which requires JavaScript to operate.
+
+
+
+ Render Me
+
+
+
+
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..b8ff60c
--- /dev/null
+++ b/index.js
@@ -0,0 +1,121 @@
+function error(msg) {
+ const elem = document.getElementById("error");
+ elem.innerText = msg;
+ elem.classList.remove("hidden");
+}
+
+let device;
+let shaderModule;
+
+async function init() {
+ const unsupportedBrowser = document.getElementById("unsupported-browser");
+ if (navigator.gpu) {
+ unsupportedBrowser.classList.add("hidden");
+ } else {
+ return;
+ }
+
+ const adapter = await navigator.gpu.requestAdapter();
+ if (!adapter) {
+ error(
+ "failed to get adapter from navigator.gpu. it looks like your environment does not have a GPU or is not supported."
+ );
+ unsupportedBrowser.classList.remove("hidden");
+ return;
+ }
+
+ device = await adapter.requestDevice();
+ if (!device) {
+ error(
+ "failed to get device from WebGPU adapter. it looks like your environment does not have a GPU or is not supported."
+ );
+ unsupportedBrowser.classList.remove("hidden");
+ return;
+ }
+
+ const shaderResp = await fetch("mandelbrot.wgsl");
+ if (!shaderResp.ok) {
+ error("failed to load shader");
+ return;
+ }
+ const shader = await shaderResp.text();
+
+ shaderModule = device.createShaderModule({
+ code: shader,
+ });
+
+ document.getElementById("render-me").addEventListener("click", doStuff);
+}
+
+async function doStuff() {
+ const output = device.createBuffer({
+ size: 1000,
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
+ });
+ const stagingBuffer = device.createBuffer({
+ size: 1000,
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
+ });
+
+ const bindGroupLayout = device.createBindGroupLayout({
+ entries: [
+ {
+ binding: 0,
+ visibility: GPUShaderStage.COMPUTE,
+ buffer: {
+ type: "storage",
+ },
+ },
+ ],
+ });
+
+ const bindGroup = device.createBindGroup({
+ layout: bindGroupLayout,
+ entries: [
+ {
+ binding: 0,
+ resource: {
+ buffer: output,
+ },
+ },
+ ],
+ });
+
+ const computePipeline = device.createComputePipeline({
+ layout: device.createPipelineLayout({
+ bindGroupLayouts: [bindGroupLayout],
+ }),
+ compute: {
+ module: shaderModule,
+ entryPoint: "main",
+ },
+ });
+
+ const commandEncoder = device.createCommandEncoder();
+ const passEncoder = commandEncoder.beginComputePass();
+ passEncoder.setPipeline(computePipeline);
+ passEncoder.setBindGroup(0, bindGroup);
+ passEncoder.dispatchWorkgroups(Math.ceil(1000 / 64));
+ passEncoder.end();
+ commandEncoder.copyBufferToBuffer(
+ output,
+ 0, // source offset
+ stagingBuffer,
+ 0, // destination offest
+ 1000
+ );
+
+ device.queue.submit([commandEncoder.finish()]);
+
+ await stagingBuffer.mapAsync(
+ GPUMapMode.READ,
+ 0, // offset
+ 1000 // length
+ );
+ const copyArrayBuffer = stagingBuffer.getMappedRange(0, 1000);
+ const data = copyArrayBuffer.slice();
+ stagingBuffer.unmap();
+ console.log(new Float32Array(data));
+}
+
+init();
diff --git a/mandelbrot.wgsl b/mandelbrot.wgsl
new file mode 100644
index 0000000..6d53156
--- /dev/null
+++ b/mandelbrot.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0)
+var output: array;
+
+@compute @workgroup_size(64)
+fn main(
+ @builtin(global_invocation_id)
+ global_id : vec3u,
+
+ @builtin(local_invocation_id)
+ local_id : vec3u,
+) {
+ // Avoid accessing the buffer out of bounds
+ if (global_id.x >= 1000) {
+ return;
+ }
+
+ output[global_id.x] =
+ f32(local_id.x);
+}
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..4feb36b
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,7 @@
+# doesn't work.
+let moz_overlay = import (builtins.fetchTarball "https://github.com/mozilla/nixpkgs-mozilla/archive/9b11a87c0cc54e308fa83aac5b4ee1816d5418a2.tar.gz");
+in
+
+{ pkgs ? import { overlays = [ moz_overlay ]; } }: pkgs.mkShell {
+ packages = [ pkgs.latest.firefox-nightly-bin ];
+}