webatintel / aquarium

BSD 3-Clause "New" or "Revised" License
24 stars 7 forks source link

Performance of WebGPU Javascript version to its native counterparts #118

Open samdauwe opened 4 years ago

samdauwe commented 4 years ago

Hi,

Thanks for providing a native implementation of the well known WebGL Aquarium scene using the not yet finished WebGPU specification. This project nicely brings together different aspects of a more complex scene such as: MSAA, instanced draws, MIP mapping, Cube maps, etc.

I could not yet find a javaScript version of the Aquarium scene using the WebGPU API, so I had a look into porting the 'aquarium-optimized' version to TypeScript which transpiles to JavaScript. I followed the native implementation as close as possible and added type information similar to the native version. Therefore the code has types such as int, uint32_t, size types that are all aliases of a TypeScript number. To reduced the amount of files, I grouped texture and model classes into single files.

The WebGPU API is very similar to the Dawn api so a one-to-one mapping was very straightforward. I only struggled with the textures:

Below you can find a screenshot of the current version. Every entity from the scene is enabled, except the inner globe (due to the cube map issue described above).

aquarium_v0 0 1

The screenshot below shows the full scene with the (faulty) inner globe enabled.

aquarium_cube_map_issue

As a reference, the latest code is available in this git repo, I also pushed an online demo on this link. Chrome Canary with the enable-unsafe-webgpu flag set is needed in order to see the online demo. Other browsers such as firefox nighly were not tested yet.

There are still some todos left for the next weeks. It might be interesting to evaluate the performance of this WebGPU version to its native counterparts in the future.

Are there any plans to add other aspects from the WebGL Aquarium scene, such as view switching and bubbles?

Best regards, Sam

hujiajie commented 4 years ago

@samdauwe That's cool!

Mip maps were not properly rendered. Most of the meshes appeared with a gray texture, only the seaweed texture was more or less ok. Each mip map appeared correct on a canvas but not on the mesh. I could not really find the cause of the issue so I used an alternative approach from here.

We have been generating the mipmaps by CPU because of previous Dawn limitation, which is unfortunate. It seems the limitation has been resolved in Dawn recently, so I can improve the relevant C++ code next.

At this moment I have not figured out how to properly render a cube map. The arrayLayerCount parameter seems to be missing on the SamplerDescriptor. Setting a depth of 6 in the size parameter of the SamplerDescriptor, resulted in no errors but the resulting Cube map is not as expected. Maybe I overlooked something, but further testing is needed.

In the WebGPU spec, arrayLayerCount was merged into depth a few weeks ago, but I'm not sure if the change has landed in Chrome Canary.

There are still some todos left for the next weeks. It might be interesting to evaluate the performance of this WebGPU version to its native counterparts in the future.

I'm curious about this, too.

Are there any plans to add other aspects from the WebGL Aquarium scene, such as view switching and bubbles?

I cannot promise a timeline yet, but that would be nice to have, among other todos.

And I'm also exploring a WebGPU port of Aquarium, but taking a different approach from yours, by transpiling the C++ code with Emscripten. It would be interesting to compare the performance of the three ports (native, WebAssembly, and hand-written TS/JS) then.

samdauwe commented 4 years ago

@samdauwe That's cool!

Thanks, I am happy you like it!

Mip maps were not properly rendered. Most of the meshes appeared with a gray texture, only the seaweed texture was more or less ok. Each mip map appeared correct on a canvas but not on the mesh. I could not really find the cause of the issue so I used an alternative approach from here.

We have been generating the mipmaps by CPU because of previous Dawn limitation, which is unfortunate. It seems the limitation has been resolved in Dawn recently, so I can improve the relevant C++ code next.

Good to know that the limitation has been resolved! Looking forward to see an improved (more cleaner) way of generating the mipmaps.

At this moment I have not figured out how to properly render a cube map. The arrayLayerCount parameter seems to be missing on the SamplerDescriptor. Setting a depth of 6 in the size parameter of the SamplerDescriptor, resulted in no errors but the resulting Cube map is not as expected. Maybe I overlooked something, but further testing is needed.

In the WebGPU spec, arrayLayerCount was merged into depth a few weeks ago, but I'm not sure if the change has landed in Chrome Canary.

The latest published TypeScript type definitions for WebGPU are 2 months old. But, more recent definitions are available on the Github repo, but it is difficult to know if those definitions are actually implemented by Chrome Canary or just kept in sync with the spec.

There are still some todos left for the next weeks. It might be interesting to evaluate the performance of this WebGPU version to its native counterparts in the future.

I'm curious about this, too.

Are there any plans to add other aspects from the WebGL Aquarium scene, such as view switching and bubbles?

I cannot promise a timeline yet, but that would be nice to have, among other todos.

Those other todos seem more important to me than the view switching and bubbles. Especially the task Rework window system binding seems a lot of work. In case you don't want to start from scratch, this header only application wrapper might be worth checking out. Once I am further with the TS/JS I could have a look into some of those todos.

And I'm also exploring a WebGPU port of Aquarium, but taking a different approach from yours, by transpiling the C++ code with Emscripten. It would be interesting to compare the performance of the three ports (native, WebAssembly, and hand-written TS/JS) then.

That is great news! I am most interested in the native <-> WebAssembly comparison. Native should be faster, but with the high focus on WebAssembly on the web and in native wasm vms (i.e. wasmtime) the differences should become smaller over time.

Best regards, Sam

hujiajie commented 4 years ago

@samdauwe I just realized that I had ever heard the momentum of sokol some time ago, but not sure about its maturity, i.e. if there's any high-profile adopter. My radar somehow missed it before, thanks for mentioning that.

Once I am further with the TS/JS I could have a look into some of those todos.

Patches are welcome!

samdauwe commented 4 years ago

@samdauwe I just realized that I had ever heard the momentum of sokol some time ago, but not sure about its maturity, i.e. if there's any high-profile adopter. My radar somehow missed it before, thanks for mentioning that.

Indeed, sokol headers are under active development and I don't know any high-profile adopter. Probably there are better alternatives because it seems much needed to abstract the window system binding to support multiple platforms and different rendering backends.

Once I am further with the TS/JS I could have a look into some of those todos.

Patches are welcome!

Good to know, I already have some ideas for possible patches :)

JiangYizhou commented 4 years ago

@samdauwe According to the pictures above I think the textures on fishes are upside down so it looks strange. You can try to flip the textures and it should looks better.

samdauwe commented 4 years ago

@samdauwe According to the pictures above I think the textures on fishes are upside down so it looks strange. You can try to flip the textures and it should looks better.

Yes, you are right! The flip variable from the Texture class was not properly used. This has been fixed, it looks better now.

aquarium_flipped_images

Ignoring the inner globe for now, I am looking now in the placement of the meshes. The native version on Linux looks like this (with the inner globe disabled).

aquarium_linux

samdauwe commented 4 years ago

@samdauwe According to the pictures above I think the textures on fishes are upside down so it looks strange. You can try to flip the textures and it should looks better.

Yes, you are right! The flip variable from the Texture class was not properly used. This has been fixed, it looks better now.

aquarium_flipped_images

Ignoring the inner globe for now, I am looking now in the placement of the meshes. The native version on Linux looks like this (with the inner globe disabled).

aquarium_linux

I found the issue of the strange mesh placement. The per instance uniforms were set to the same (referenced) value because in JavaScript the assignment operator copies the object reference to the uniforms instead of taking a copy. Manually copying the uniforms resolved the problem. The result is starting to look closer to the native version.

AquariumEdge

I had to switch to the latest Microsoft Edge Canary Version 85.0.538.0 to get the result because the scene does not render anymore in the latest Chrome Canary Version 85.0.4166.1 of this weekend. When loading the scene in Chrome Canary, my screen flickers black and the resulting scene is also black, and no errors are shown on the console. Probably, Edge is on an older WebGPU implementation compared to Chrome, I will wait to the next Chrome release before starting to debug the issue.

gyagp commented 4 years ago

@samdauwe, thanks for the great work on this! The Chrome issue looks like a regression. Could you please bisect (https://www.chromium.org/developers/bisect-builds-py), report a Chrome issue at http://crbug.com/new, and paste the bug link here? We will follow up the fix in Chrome.

samdauwe commented 4 years ago

@gyagp, thanks for the links on how submit a Chrome issue!

The bug link is as follows: Issue 1092227: WebGPU aquarium scene fails to render, the resulting canvas is black

Note that I get the following warning on the console: Error

Which I did not get in an older Chrome version. However, setting the arrayLayer value on the .origin.z silenced the deprecation warning but did not make any difference. So either other changes are needed to make the scene work according to the latest WebGPU spec or there is actually an issue in Chrome.

gyagp commented 4 years ago

Thanks for reporting and we'll investigate it soon!