Help needed in migrating from WebGL to WebGPU

Hello, in a third party library that I am currently using uses three.js, and it has performance issue that can’t be optimized further (without sacrificing rendering quality), therefore, I would like to see if this library can use WebGPU instead and made some changes in a fork. However, there is an error message that I don’t know how to interpret, could anyone take a look and give some suggestions on what should I focus on next? Any suggestions is appreciated!

The error message itself:

WebGPURenderer.js:241 Uncaught TypeError: Cannot read properties of null (reading 'updateFrame')
    at WebGPURenderer.render (WebGPURenderer.js:241:15)
    at Function.tick (three-render-objects.js:99:24)
    at comp.<computed> [as tick] (kapsule.module.js:195:65)
    at animate (index.html?editors=1111&key=index.html-c8560842-cc47-5b21-9bfe-c919c4fb7ce7:66:17)
    at index.html?editors=1111&key=index.html-c8560842-cc47-5b21-9bfe-c919c4fb7ce7:68:7

Codepen: https://codepen.io/xiaoxiaobt/pen/yLKGqjG?editors=1111

GitHub: three-render-objects/index.html at c5727ad548fa4663a0e54961f6224cc9ccb4ad26 · xiaoxiaobt/three-render-objects · GitHub

Unfortunately, it is unlikely that simply switching to WebGPURenderer will improve the performance of your scene today. WebGPU is not necessarily magically faster at rendering the same shaders and draw calls, it provides more tools and low-level control to applications to optimize things. We’re still in the process of getting WebGPU to be 100% compatible with previous three.js content, it’s not stable yet, and I don’t think implementing those low-level optimizations is happening yet.

and it has performance issue that can’t be optimized further (without sacrificing rendering quality),

It’s very unlikely that your content can’t be optimized further. What performance limitations are you reaching? How many draw calls, vertices, and texture memory are used? If you want to share the original WebGL scene we can probably help suggest ways to optimize it without hurting the quality.

2 Likes

Sorry for replying late and thank you for your answer! I see, seems like WebGPU still requires some time to be perfect. The reason why I thought WebGPU could be a good option in the first place was that, the WebGPU version of instanced mesh (three.js - WebGPU - Instance Mesh) ran 60 fps on my laptop but the similar WebGL version (three.js examples) only ran at 40 fps at that time (now it’s again 60 fps, weird😅). I tried to demonstrate this by forking the repo and increasing the number of instances to 20x20x20, but then WebGPU version (three.js - WebGPU - Instance Mesh) unfortunately no longer works (due to hardware limit?), but the WebGL version (three.js webgl - instancing - dynamic) still works fine.

My use case is a 3d-force-graph that simulates forces between objects. The computational heavy part is on CPU, and rendering takes roughly 30% of time during a cycle. Although it is not a big part, it would still be nice to have some speed up if possible, and I’ve heard that WebGPU does not block the main thread (which was one of the reasons why I wanted to experiment this, maybe I was wrong). I do not expect anyone to provide me a ready-made solution as the topic is a bit far away from three.js at this point, but if you see some irregular behaviors from the frame graph which I couldn’t recognize please let me know, it could be something I can work on :+1::+1:

Example: https://vasturiano.github.io/3d-force-graph/example/large-graph/
Source (not that relevant): 3d-force-graph/index.html at 412cade7c0ece9dc92f71debaccebad9dea1681c · vasturiano/3d-force-graph · GitHub

P.S. I’ve checked the release note of R144, and it seems like the three-nodes has been renamed, which is a really nice thing for WebGPU part​:smile::smile:

If the main cost is computing a force graph layout frequently, and that currently happens on the CPU, I think you do have a few ideas:

a. if the inputs are fixed, consider precomputing the animation
b. consider keeping computation on the CPU, but moving it to a Web Worker
c. move force graph layout to WASM
d. move force graph layout to WebGL 2 with Transform Feedback
e. move force graph layout in WebGPU

My hunch would be that a Web Worker is a good option here, and probably the easiest of the options above. You would also have the option of computing the force graph layout at a lower framerate (e.g. 10 fps) in a Web Worker, and just interpolating between those computed frames at 60fps while rendering on the main thread.

1 Like

Yes, I also think using a web-worker is a good idea, I will try to implement that. Thank you again for your help!

1 Like

One more idea — I just stumbled across this project recently, for GPU-accelerated force graph layouts: