Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Browser WebAssembly Port #5106

Draft
wants to merge 23 commits into
base: master
Choose a base branch
from
Draft

Conversation

ading2210
Copy link

@ading2210 ading2210 commented May 30, 2024

Agreement

By creating a pull request in stk-code, you hereby agree to dual-license your contribution as
GNU General Public License version 3 or any later version and
Mozilla Public License version 2 or any later version.

This includes your previous contribution(s) under the same name of contributor.

Keep the above statement in the pull request comment for agreement.

I ported SuperTuxKart to the web using Emscripten, and I think it would be worthwhile to have this merged upstream.

Here's a working demo: https://supertuxkart.pages.dev/

I tested this on Chrome 125 and Firefox ESR 115.

8mb.video-Q5u-I6rcrEhf.mp4

Working features:

  • The game launches
  • OpenGL ES 2 graphics (GLES 3 doesn't work)
  • Audio
  • Persistent user data
  • Caching data and asset files in IndexedDB

TODO:

  • Fix GLES 3 (maybe someone with more experience in webgl could help here)
  • Webpage theming
  • Better compression for assets
  • Lazy load assets during gameplay
  • Networking

Caveats:

  • The RAM usage is rather high because the assets are always loaded in memory
  • The performance isn't great, probably because the legacy renderer is still being used.
  • There is a large ~700MB download required immediately
  • Some options, like anything related to online multiplayer, may hang the game

@ading2210 ading2210 marked this pull request as draft May 30, 2024 14:45
@CodingJellyfish
Copy link
Member

This is so cool!

@CodingJellyfish
Copy link
Member

CodingJellyfish commented May 30, 2024

You don't need to worry about the graphics API thing. If I complete the Vulkan engine I will probably write a WGPU engine.
Also, there's a compressed asset for Android to load faster, or the whole WASM version should probably use the same code as Android. I don't know much about this, you could ask @deveee for help.

@CodingJellyfish
Copy link
Member

If the commits don't create any regressions, I guess I could merge it as quickly as possible. The todos can be done in later PRs or by other contributors. But I would like a clear instruction on how to compile this in INSTALL.md.

@ading2210
Copy link
Author

Also, there's a compressed asset for Android to load faster, or the whole WASM version should probably use the same code as Android.

Personally I don't think using the same code as the Android version would be a good idea here, since Android is vastly different from the Emscripten environment. For example in WASM the threading implementation is very broken, which means a large amount of the networking logic has to be rewritten to use async APIs for it to work. I did borrow the audio patches from the Switch port though, since those allowed the audio processing to run in the main thread (because web audio cannot be run from a worker at all).

Regarding the graphics issues, when I tried using the non-legacy renderer, I kept getting WebGL errors which I wasn't able to debug. You can try removing the #ifndef here to see how far you can get with that:

#ifndef __EMSCRIPTEN__
if (CreationParams.ForceLegacyDevice)
#endif

image

Also, I did put compile instructions inside the README for the wasm directory, but I guess this got buried in the PR diff.

@CodingJellyfish
Copy link
Member

Thanks for mentioning. Actually, I meant the Android code could handle the option of installing the full uncompressed game asset instead of forcing you to load that initially. I don't compile Android code so I don't know a lot tbh.

@CodingJellyfish
Copy link
Member

And yes I found the instructions now, very thanks. Then I would approve the merge of this PR at any time when you feel free.

@ading2210
Copy link
Author

I do think that I can incorporate what android/generate_assets.sh does to compress the assets further, which would be great for decreasing the initial download size. However loading all of the assets in memory is an Emscripten limitation, rather than something in STK's code. All of the C++ APIs to read files are synchronous, but Javascript has no synchronous API for reading files from the disk. This means that Emscripten's virtual filesystem has to be loaded in memory at all times. Even if it could be backed up something like an IndexedDB, Emscripten still has to be able to read any file from it instantly. The Emscripten docs have some more info on this.

If I can get the assets compressed down to under ~200MB or so, then that amount of extra memory usage is more acceptable and we won't need to worry about the Emscripten virtual filesystem stuff.

@thiccaxe
Copy link

another task is to either strip out or parse the ANSI escape sequences

@ading2210
Copy link
Author

ading2210 commented May 31, 2024

stk_wasm_2.mp4

I just made some improvements to the web interface. The most significant changes are that the game now fills the entire browser window, and the progress for the asset download is displayed.

@Alayan-stk-2
Copy link
Collaborator

It's cool to have STK running in a web browser.

But I have some concerns. The OpenGL ES 2 graphics mean that the game looks really crappy, and at the same time I get really terrible performance. Running the benchmark I got a steady FPS of 6 and the game was running at 50% of real-time-speed (it took 1m13s to complete instead of normally about 36s). I get something like 250FPS with a normal compiled version using Graphics 1.

If someone is curious about STK, I'd prefer them to not play the web version as a way to test the game...

I had a cursory look at the changes, most of it seem to be compiling logic and define guards, plus the webpage code. It seems to be relatively simple overall, but the maintenance burden still appears to be an open question.

Especially as additional code would arguably be needed to disable the parts and options that don't work on the web version.

@searinminecraft
Copy link
Contributor

searinminecraft commented Jun 14, 2024

to anyone that wants to try this you might wanna disable ublock origin as it blocks webassembly

if youre using a hardened by default browser (e.g. librewolf, mulch, ungoogled-chromium, etc.) you may need to find a way to enable jit, webgl and wasm

@ading2210
Copy link
Author

ading2210 commented Jun 26, 2024

I managed to get the assets compressed down to 120MB, which is a large improvement over the 700MB download that was required before. The memory usage is also significantly lower since less asset data gets loaded into memory.

The highest levels of compression cause the textures to be noticeably blurry sometimes, so I added an option to use higher resolution assets at the cost of a larger download.

@CodingJellyfish
Copy link
Member

Hello, is there any progress on this?

@ading2210
Copy link
Author

@CodingJellyfish I just merged the latest commits on the main branch with my changes. I'll probably be able to fix the networking problems by switching from the blocking libcurl APIs to the async ones. Once the networking is fixed I'll likely be fine with merging this PR. I don't have any experience in graphics programming so I can't fix the GLES 3 support, so someone else will probably have to do it later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants