• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html>
2<title>Web GPU Demo</title>
3<meta charset="utf-8" />
4<meta http-equiv="X-UA-Compatible" content="IE=edge">
5<meta name="viewport" content="width=device-width, initial-scale=1.0">
6<!-- For *.skia.org https://developer.chrome.com/origintrials/#/registration/2983494015644598273
7     Expires Nov 19, 2021
8     -->
9<meta http-equiv="origin-trial" content="AnRs8mYss+Awd1DPUg2VfjXJbw2087/Dysaa3L7JmrbzTkwoEr87cX3y0zUfTGOFSLKJLRqNEmFAwfy+uumVXQsAAABbeyJvcmlnaW4iOiJodHRwczovL3NraWEub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJHUFUiLCJleHBpcnkiOjE2NDMxNTUxOTksImlzU3ViZG9tYWluIjp0cnVlfQ==">
10
11<!-- For localhost:8123 https://developer.chrome.com/origintrials/#/registration/6568359319031513089
12     Expires Nov 19, 2021
13     -->
14<meta http-equiv="origin-trial" content="ArQyw1ckz8lMOAcs5BbhOVJh2A6KMhYL6w/rTjPNnViqZyfFhlyJ5hnuHARoCkS1ZKiJi+YbsFvPWy23ePkFMQgAAABJeyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgxMjMiLCJmZWF0dXJlIjoiV2ViR1BVIiwiZXhwaXJ5IjoxNjQzMTU1MTk5fQ==">
15
16<style>
17  canvas {
18    border: 1px dashed grey;
19  }
20</style>
21
22<body>
23  <h1>WebGPU Test</h1>
24  <pre id="log"></pre>
25
26  <canvas id=draw width=500 height=500></canvas>
27</body>
28
29<script type="text/javascript" charset="utf-8">
30  if ("gpu" in navigator) {
31    log("WebGPU detected")
32    WebGPUDemo();
33  } else {
34    log("No WebGPU support.")
35  }
36
37  function log(s) {
38    document.getElementById("log").innerText = s;
39  }
40
41  async function WebGPUDemo() {
42    // Adapted from https://github.com/austinEng/webgpu-samples/blob/main/src/sample/helloTriangle/main.ts
43    const adapter = await navigator.gpu.requestAdapter();
44    if (!adapter) {
45      log("Could not load an adapter. For Chrome, try running with --enable-features=Vulkan --enable-unsafe-webgpu");
46      return;
47    }
48
49    const device = await adapter.requestDevice();
50    console.log(adapter, device);
51    const canvas = document.getElementById("draw");
52    const context = canvas.getContext('webgpu');
53    if (!context) {
54      log("Could not load webgpu context");
55      return;
56    }
57    console.log(context);
58
59    const devicePixelRatio = window.devicePixelRatio || 1;
60    const presentationSize = [
61      canvas.clientWidth * devicePixelRatio,
62      canvas.clientHeight * devicePixelRatio,
63    ];
64    const presentationFormat = context.getPreferredFormat(adapter);
65
66    context.configure({
67      device,
68      format: presentationFormat,
69      size: presentationSize,
70    });
71
72    const triangleVertWGSL = `[[stage(vertex)]]
73fn main([[builtin(vertex_index)]] VertexIndex : u32)
74     -> [[builtin(position)]] vec4<f32> {
75  var pos = array<vec2<f32>, 3>(
76      vec2<f32>(0.0, 0.5),
77      vec2<f32>(-0.5, -0.5),
78      vec2<f32>(0.5, -0.5));
79
80  return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
81}`;
82
83    const redFragWGSL = `[[stage(fragment)]]
84fn main() -> [[location(0)]] vec4<f32> {
85  return vec4<f32>(1.0, 0.0, 0.0, 1.0);
86}`;
87
88    const pipeline = device.createRenderPipeline({
89      vertex: {
90        module: device.createShaderModule({
91          code: triangleVertWGSL,
92        }),
93        entryPoint: 'main',
94      },
95      fragment: {
96        module: device.createShaderModule({
97          code: redFragWGSL,
98        }),
99        entryPoint: 'main',
100        targets: [
101          {
102            format: presentationFormat,
103          },
104        ],
105      },
106      primitive: {
107        topology: 'triangle-list',
108      },
109    });
110
111    console.log(pipeline);
112
113    const startTime = Date.now();
114    function frame() {
115      const now = Date.now();
116      const commandEncoder = device.createCommandEncoder();
117      const textureView = context.getCurrentTexture().createView();
118
119      const renderPassDescriptor = {
120        colorAttachments: [
121          {
122            view: textureView,
123            loadValue: {
124              r: Math.abs(Math.sin((startTime - now) / 500)),
125              g: Math.abs(Math.sin((startTime - now) / 600)),
126              b: Math.abs(Math.sin((startTime - now) / 700)),
127              a: 1.0 },
128            storeOp: 'store',
129          },
130        ],
131      };
132
133      const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
134      passEncoder.setPipeline(pipeline);
135      passEncoder.draw(3, 1, 0, 0);
136      passEncoder.endPass();
137
138      device.queue.submit([commandEncoder.finish()]);
139      requestAnimationFrame(frame);
140    }
141
142    requestAnimationFrame(frame);
143  }
144</script>