WebGPU — From Ping Pong WebGL To Compute Shader 🖥️
We’ve finally arrived at one of the most exciting and powerful features of WebGPU: the compute shader. This is a whole new API built with…
WebGPU — From Ping Pong WebGL To Compute Shader 🖥️
We’ve finally arrived at one of the most exciting and powerful features of WebGPU: the compute shader. This is a whole new API built with modern GPU architecture in mind. My first real deep dive into this technique was thanks to one insanely awesome legend, who introduced me to GPU computation in WebGL. Back then, the approach involved using 2 ping-pong off-screen rendering (Framebuffer Objects, FBO) to store data, and things got pretty complex, especially when you add parallel computation or post-processing FX into the mix.

Compute Shader, Thread, Workgroup
One major shift with compute shaders is that you no longer think in terms of pixels — instead, you work with threads grouped into workgroups. These workgroups form a kind of grid, and they get mapped to the GPU’s hardware to run tasks in parallel. This makes compute shaders super efficient for certain types of heavy computation.
const WORKGROUP_SIZE = 32;
const workgroupCount = Math.ceil(inBuffer.particleCount / WORKGROUP_SIZE);
wpass.dispatchWorkgroups(workgroupCount);
For workgroup_size, you want enough threads to keep the GPU busy, but not so many that you exceed hardware limits or waste resources.
Storage Buffer
Another game-changer is the introduction of storage buffers, especially in our intermediate particle system. Back in WebGL days, you had to use one render target to read data from the previous frame and another to write results for the next, because it’s not allowed to read and write to the same buffer. I guess it’s because of the cumbersome FBO workaround that makes the WebGPU API came up with this new Storage Buffer. We can update the computed data in a single buffer in place without swapping read and write in the render loop.
Here is the comparison of the 2 solutions:

The diff view of my Visual Studio Code
As you can see, the left side used 2 in and out buffers as the WebGL workflow, whereas the right one, I can simplify them by just using 1 for read and write. Also, when this method is called from the render loop, we don’t have to pass in/out buffers as arguments ( line 127–128 ) anymore.
MediaPipe & Web Speech API
For some added AI/ML fun, I’ve also been experimenting with Google’s MediaPipe and the Web Speech API. Both are pretty mature and widely used for image and voice recognition. However, there’s a small catch — due to browser security constraints, the Web Speech API doesn’t let you keep the mic open too long. On my Android phone, for example, it keeps popping up a “microphone in use” notification. Yeah… not a great UX, but hey — this is just for learning purposes, so hopefully no one minds 😅.

Left up : visualize overlapped landmarks. Left down : need to calculate the UV of recognized letters in particle texture map. Right : real-time generate face mesh
Wrapping Up
A funny discovery during all this: my Android devices struggle to run this app, not because of the GPU, but because of the CPU load from running MediaPipe! The frame rate tanks unless I turn that part off. Ironically, my Pixel phone can handle 5x more particles with ease when MediaPipe is disabled.
[embed]The Breakdown on Youtube
Learning WebGPU compute shaders has been an exciting experience. From ping-pong to compute shader and AI integrations, I feel like I’ve barely scratched the surface. But I’m excited to keep building, breaking, and learning.
Deploy link you can try : https://dreamy-biscotti-272e4c.netlify.app/
메타데이터
- post_id
- 1ab3d8a461e2
- slug
- webgpu-from-ping-pong-webgl-to-compute-shader-️-1ab3d8a461e2
- url
- https://medium.com/phishchiang/webgpu-from-ping-pong-webgl-to-compute-shader-%EF%B8%8F-1ab3d8a461e2
- canonical_url
- https://medium.com/phishchiang/webgpu-from-ping-pong-webgl-to-compute-shader-%EF%B8%8F-1ab3d8a461e2
- author_url
- https://medium.com/@phishchiang
- status
- ok
- fetched_at
- 2026-06-26 08:21:59