supertuxkart / stk-code

The code base of supertuxkart
Other
4.37k stars 1.03k forks source link

Web support via emscripten? #3943

Closed Mstrodl closed 5 years ago

Mstrodl commented 5 years ago

Hi all, I built this over a long weekend project and realized it could be useful!

qwertychouskie commented 5 years ago

Hmm, interesting! Is there a hosted version I can try somewhere?

This could potentially be interesting to have a hosted demo on https://supertuxkart.net.

Also it seems like the work is based on a master from late 2018, would you be willing to rebase the changes onto the current master?

Mstrodl commented 5 years ago

@qwertychouskie I'm not sure I can do too much, in case the code didn't make it super clear, I've never touched c++ or emscripten before this so everything's new to me! That being said, I should be able to pull something together on github.io! I'll try and bring it up to date, but I can't make too many promises on that

Mstrodl commented 5 years ago

@qwertychouskie Looks like Gitlab and Github pages both don't like the huge (~623MB) data file. So I've got it running here (Be cautious as it will probably lock up the browser for some time depending on the vendor and the single-core abilities of your CPU and WILL blow through metered connections, although after initial page load it should be cached in IndexedDB!)

Benau commented 5 years ago

Please don't open wip pr

Mstrodl commented 5 years ago

@Benau It's only WIP because it only runs under Emscripten at the moment with my changes and I wasn't even entirely sure it would be a welcome change

ghost commented 5 years ago

You might try to compress the assets using the android script and then copying the files in data to where you need them.

Mstrodl commented 5 years ago

@cddepppp256 Running that script now, although I think maybe in the long-term it could be cool if we could package them in groups that we load on-demand (e.g. one group for each kart, one group for each track, and an "entrypoint" group with everything else)

Benau commented 5 years ago

Sorry.. because i don't like spam from PRs. I would suggest this should belong to a forum post so we can interact better

https://forum.freegamedev.net/viewforum.php?f=17

Alayan-stk-2 commented 5 years ago

A few things:

ghost commented 5 years ago

I have video but I have to split first

Mstrodl commented 5 years ago

@Alayan-stk-2

ghost commented 5 years ago

@Benau :

Sorry.. because i don't like spam from PRs. I would suggest this should belong to a forum post so we can interact better

https://forum.freegamedev.net/viewforum.php?f=17

@Alayan-stk-2 :

WIP code that can't be properly tested and reviewed is not welcome in PRs. You can ask people to test your branch or your demo but we prefer to not have experimental unready code sitting in PRs.

I guess I can agree with this standpoint.

The web version has zero advantage over a local version in almost all environments. Only extremely locked down environments where it is not possible to run an executable which has not been pre-approved are an exception.

So if "extremely locked down environments" are an exception, then there's not zero advantage?

The performance is abysmal. I got the outdated openGL support message because it is unable to properly use the graphics card, and it has been sitting frozen for several minutes now after starting a race. Qwerty suggested to potentially use it for a demo, I'm strongly against this idea. Playing a demo with broken graphics and awful performance is the worse possible kind of demo we could do.

Yes, after seeing the preformance, it's not very good. For me, it started after 2 min. It's only really good for things like Math Class, but it works!

Considering this, the burden of having to maintain the web support is not worth it, while merging it in master would imply we'd accept dealing with tickets about issues specific to STK through a web browser.

I thought this was already implied through all your other points?

Running everything through a web browser as if it was a kind of OS is a stupid trend anyway

I agree that it is, but if there can be support that would be nice.

Mstrodl commented 5 years ago

I've put another page that uses the latest master and has compressed assets (from the android script) and load time isn't anywhere near as bad. Most of the times where it blocks is because of big IO operations, which makes sense since STK uses synchronous FS operations

Mstrodl commented 5 years ago

Perhaps in the future we could use a Worker for the main loop and another Worker for the audio. Currently I:

ghost commented 5 years ago

https://streamable.com/2z8my (not master version)

Mstrodl commented 5 years ago

@cddepppp256 If possible, maybe try running it in chrome/chromium? Most of my testing has been on it and it seems to perform much better. Master version still hasn't finished loading for me in firefox in ~8 minutes, so it's probably not going to get much better from there.

ghost commented 5 years ago

@Mstrodl I will try!

Mstrodl commented 5 years ago

Actually, looks like firefox killed STK because it was blocking... After trying again, it loaded in some 20s.

Here is STK running in firefox with FPS showing at 16/19/20: image

And here is it running in Chromium with FPS showing 23/40/42: image

Also: could it be that firefox isn't using hardware acceleration for 3D?

ghost commented 5 years ago

I also had some tabs open so that might be part of it.

ghost commented 5 years ago

Screenshot from 2019-05-28 13-44-15

Mstrodl commented 5 years ago

@cddepppp256 Didn't even consider that, I had a few open in Chromium, but chromium is multi-process unlike Firefox... Here's it running in Chromium. Note FPS looks a bit lower, but that's likely just because I'm recording it which takes up resources. I'm running Chromium 74.0.3729.169 on an Intel i7-7500U (4) @ 3.500GHz using integrated GPU: image

ghost commented 5 years ago

Screenshot from 2019-05-28 13-58-59

ghost commented 5 years ago

CPU:

model name  : Intel(R) Pentium(R) CPU  N3540  @ 2.16GHz

Intel HD 3000 CPU Graphics

ghost commented 5 years ago

Here's my WebGL report:

Screenshot_2019-05-28 WebGL Report

WEBGL2

ghost commented 5 years ago

https://www.youtube.com/watch?v=tMApGusjjeg

Mstrodl commented 5 years ago

@cddepppp256 Looks like I wasn't actually serving the /master page and was actually serving / because my nginx config wasn't pointing at the correct thing and I didn't notice since I was using caddy to test my local builds! Oops! I think it's fixed now, at the very least /master appears to be reporting the correct filesize (125M vs 629M) so I assume it's correct.

I'm testing now on a lower-spec'd machine to see if I can reproduce the slowness, although I'm not sure that there's much to be done for a bay trail pentium. Conveniently, it's also running Intel HD Graphics 3000! It, however, is running an i7-2640M @ 2.80Ghz. I can definitely reproduce the low FPS here. I get 5/7/7 on Chrome 72.0.3626.119. I'm going to go around trying some other machines as well I think.

Mstrodl commented 5 years ago

On a Celeron N3060 @ 1.60 Ghz, I got about the same: 5/7/8 (under Intel HD Graphics 400)... If we do this, we'll definitely need some sort of a warning that it doesn't work well on older hardware. Another thing we could try is setting the graphics settings to their lowest when running under emscripten. Luckily, this should be fairly easy to do with our existing setup:

var config_path = "/home/web_user/.config/supertuxkart/config-0.10/config.xml.";
try {
    var file = FS.stat(config_path);
} catch(err) {
    if(err.code == "ENOENT") {
        FS.writeFile(config_path, "<foo>bar</foo> <baz />");
    } else throw err;
}
ghost commented 5 years ago

Looks like I wasn't actually serving the /master page and was actually serving / because my nginx config wasn't pointing at the correct thing and I didn't notice since I was using caddy to test my local builds! Oops! I think it's fixed now, at the very least /master appears to be reporting the correct filesize (125M vs 629M) so I assume it's correct.

Ok :-P

I'm testing now on a lower-spec'd machine to see if I can reproduce the slowness, although I'm not sure that there's much to be done for a bay trail pentium. Conveniently, it's also running Intel HD Graphics 3000! It, however, is running an i7-2640M @ 2.80Ghz. I can definitely reproduce the low FPS here. I get 5/7/7 on Chrome 72.0.3626.119. I'm going to go around trying some other machines as well I think. On a Celeron N3060 @ 1.60 Ghz, I got about the same: 5/7/8 (under Intel HD Graphics 400)... If we do this, we'll definitely need some sort of a warning that it doesn't work well on older hardware.

I think you will have to.

Another thing we could try is setting the graphics settings to their lowest when running under emscripten.

I'm pretty sure that GLES2/WebGL was already at the lowest STK setting. I'm not 100% sure.

qwertychouskie commented 5 years ago

Just curious, is the build using asm.js or WebAssembly? WebAssembly might be a bit faster. Well, more than a bit faster: https://cdn-images-1.medium.com/max/800/1*JRuZIJK4YlTPrdaHQIs0Dw.png (13FPS vs 157 FPS in this benchmark!) Full article: https://medium.com/@torch2424/webassembly-is-fast-a-real-world-benchmark-of-webassembly-vs-es6-d85a23f8e193

Mstrodl commented 5 years ago

@qwertychouskie asm.js, but I just got it properly building under wasm. As it turns out, asm2wasm fails silently when using SIMD, which I've fixed. It appears to perform much better... At least until it crashes when it tries to put a float into an integer space on the level confirmation screen. I've only tested the single player option so story mode might work still. I'll push that later today if I have any luck!

Mstrodl commented 5 years ago

@qwertychouskie I was right, it seems to just be the level configuration/confirmation screen that breaks. Launching story mode seems to work fine and levels in it can be launched as well with no issues. (The confirmation screen throws this error when it is opened: float unrepresentable in integer range) I've put the wasm build on its own page to try out. I'm not entirely sure where the error is coming from though. It could be either a change from disabling SIMD or an asm2wasm bug.

So known wasm-specific issues:

qwertychouskie commented 5 years ago

Hmm, looking at the log from launching, it seems you are using an old copy of stk-code/data:

[info   ] GrandPrixManager: Loading Grand Prix files from /home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/grandprix/
[error  ] GrandPrixData: The Grand Prix file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/grandprix/2_offthebeatentrack.grandprix' contains a track 'cocoa_temple' that does not exist
[error  ] GrandPrixManager: Ignoring Grand Prix /home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/grandprix/2_offthebeatentrack.grandprix (Unknown track)

[error  ] GrandPrixData: The Grand Prix file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/grandprix/3_tothemoonandback.grandprix' contains a track 'gran_paradiso_island' that does not exist
[error  ] GrandPrixManager: Ignoring Grand Prix /home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/grandprix/3_tothemoonandback.grandprix (Unknown track)

[error  ] GrandPrixData: The Grand Prix file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/grandprix/4_atworldsend.grandprix' contains a track 'black_forest' that does not exist
[error  ] GrandPrixManager: Ignoring Grand Prix /home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/grandprix/4_atworldsend.grandprix (Unknown track)

[info   ] GrandPrixManager: Loading Grand Prix files from /home/web_user/.local/share/supertuxkart/grandprix/
[info   ] main: ended initRest
[info   ] main: init rest'd
[info   ] main: creating mainloop!
[info   ] main: mainloop init'd!
[error  ] ChallengeData: Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/candela_city.challenge'.
[warn   ] unlock_manager: An error occurred while loading challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/candela_city.challenge' : Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/candela_city.challenge'. challenge will be ignored.
[error  ] ChallengeData: Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/cocoa_temple.challenge'.
[warn   ] unlock_manager: An error occurred while loading challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/cocoa_temple.challenge' : Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/cocoa_temple.challenge'. challenge will be ignored.
[error  ] ChallengeData: Undefined or incorrect value for 'gp' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp2.challenge'.
[warn   ] unlock_manager: An error occurred while loading challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp2.challenge' : Undefined or incorrect value for 'gp' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp2.challenge'. challenge will be ignored.
[error  ] ChallengeData: Undefined or incorrect value for 'gp' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp3.challenge'.
[warn   ] unlock_manager: An error occurred while loading challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp3.challenge' : Undefined or incorrect value for 'gp' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp3.challenge'. challenge will be ignored.
[error  ] ChallengeData: Undefined or incorrect value for 'gp' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp4.challenge'.
[warn   ] unlock_manager: An error occurred while loading challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp4.challenge' : Undefined or incorrect value for 'gp' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/gp4.challenge'. challenge will be ignored.
[error  ] ChallengeData: Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/granparadiso_island.challenge'.
[warn   ] unlock_manager: An error occurred while loading challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/granparadiso_island.challenge' : Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/granparadiso_island.challenge'. challenge will be ignored.
[error  ] ChallengeData: Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/green_valley.challenge'.
[warn   ] unlock_manager: An error occurred while loading challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/green_valley.challenge' : Undefined or incorrect value for 'track' in challenge file '/home/heatingdevice/projects/stk-code/cmake_build/opt/stk/share/supertuxkart/data/challenges/green_valley.challenge'. challenge will be ignored.

This may also be causing the crash, try fixing this and re-testing.

qwertychouskie commented 5 years ago

Also, here's some potentially useful info: https://emscripten.org/docs/compiling/WebAssembly.html#trapping

Mstrodl commented 5 years ago

@qwertychouskie I'll definitely try updating the data, although it doesn't entirely make sense that it would crash on wasm but not asmjs due to different data. Trapping seems to actually be exactly what we need to change which is terrific! Also: I tried getting it working under the opengl driver instead of ogles2 which unfortunately didn't work because it seems like opengl uses some legacy stuff that emscripten doesn't properly support (and when legacy opengl mode is turned on, you lose access to FULL_ES3, which is also needed....)

Mstrodl commented 5 years ago

@qwertychouskie Setting trap to clamp did fix it! But we still have the issue of gift boxes throwing index out of bounds... I did try setting trap to js as well, but it didn't fix the issue. New demo

qwertychouskie commented 4 years ago

Also, this is a great read: https://medium.com/@olydis/roller-coaster-tycoon-in-the-browser-ef6a340bced8

Has some info on optimizations, including some build parameters you could try.

qwertychouskie commented 4 years ago

Also, STK has a built-in profiler, though it requires Artist Debug Mode to be enabled. Can you perhaps change the code so that Artist Debug Mode is enabled by default? (Otherwise it requires changing config.xml to enable, which AFAIK can't be done in a browser.)

Mstrodl commented 4 years ago

@qwertychouskie I feel like wasm is a really good path to explore more. A lot of the blocking stuff can probably be solved with some browser-specific code. (SFXManager comes to mind in this case, most browsers support Vorbis natively so we could do playback on the browser-side and thus remove work from the main loop) I will certainly look into some more of the flags available a bit more from that article though!

As far as the profiler: Emscripten actually does allow us to modify the config, it exposes the FS global in the browser console. I'll look at the profiler once I can figure out what's happening with the out of bounds index. I think this may just be related to drawing the items at the top because time trials crash the game as well under wasm (at the exact moment when the items would have been drawn).

ghost commented 4 years ago

Are you going to make it more (the compilation) portable? Also, it'd be nice if you could unlock tracks (in config.xml) by default and create a default players.xml file so you don't have to go over every time you load it.

I'm trying the wasm version right now.

Mstrodl commented 4 years ago

@cddepppp256 yeah, I was actually working on making a docker container that just builds the whole thing (we have to build a bunch of dependencies for emscripten as well) today. Unlocking tracks can actually be done with a cli flag and I'm going to hopefully fix syncfs calls soon, which should mean persistent storage (which I had working a while ago, I guess an emscripten update broke it some time ago)

Mstrodl commented 4 years ago

Oops! I guess I never sent this here! I fixed the game crashing when STK tries to draw an item. It was happening because the android scripts were converting some stuff to jpg that should have been left as png. Fixed

deveee commented 4 years ago

When it converts png to jpg, it modifies information about file name in .spm files too.

Mstrodl commented 4 years ago

@deveee In this case, the android scripts were modifying stuff like the banana item icon which needs an alpha channel and is pointed at in an xml file, not an spm file.

Mstrodl commented 4 years ago

Terrific news! I've gotten my fork to compile on a normal machine as well as emscripten, which means this could be mergeable at some point! Currently, it appears as though everything other than audio is working (this is almost definitely due to a bunch of changes to sfx_manager.cpp to make it not use threads, this will need more investigation though).

The only other real issue I'm running into is just one of figuring out how I ever managed to compile most of the emscripten ports of the necessary libraries (to make it more portable so emscripten can be targetted on machines other than my own). Although perhaps they should just be in supertuxkart/dependencies?

Mstrodl commented 4 years ago

I've fixed audio on desktop build as well. The only issue now is just figuring out why the desktop app hangs when I hit the exit button. If someone's on windows, I'd appreciate if they could test as well!

Mstrodl commented 4 years ago

I've now got the entire application building properly in an isolated docker image! bash emscripten-resources/dockerRun.sh should build the entire game and all its dependencies and put artifacts in stk-code/cmake_build_docker/bin! It doesn't run the asset optimization step (yet) simply because it takes a reasonably long amount of time to compile all the dependencies every time I change something and need to test it.

@Benau Can you please reopen this pull request? I don't seem to have permissions to reopen it for some reason...

Only potential blocking issues, although they're pretty much all UX tweaks:

Other than the above, the PR should be ready to merge (I hope)!

deveee commented 4 years ago

Just looking at your first changed line I see that it's not ready to merge:

if(1 OR FREETYPE_FOUND)

There are more unacceptable modifications like changed IRRKEY to KEY_ and also I think that gays won't like you because of some #ifdefs :P

Mstrodl commented 4 years ago

@devee For some reason, the pull request isn't showing the latest changes. Please look at the repo's diff

qwertychouskie commented 4 years ago

@Mstrodl I did a quick partial look-through, and although the code looks much better, there's still some unnecessary changes such as adding extra return lines and such, see e.g. https://github.com/supertuxkart/stk-code/compare/master...Mstrodl:master#diff-3c603adb1714171ce7ec04fcc9efc310 and https://github.com/supertuxkart/stk-code/compare/master...Mstrodl:master#diff-fc7e36e420eb03f09e98e4dd0ff45d69.

Mstrodl commented 4 years ago

@qwertychouskie Thanks, I believe I've fixed the newline issue in the latest commit.

And @devee I've fixed the IRR_KEY_IRR_KEY_ thing with preprocessing. Can you please elaborate on what exactly is unacceptable with the change though? It seemed to me like an error more than anything because (at least under Emscripten), IRR_KEY_IRR_KEY_$X was undeclared but IRR_KEY_$X was. Also, perhaps you can explain your concerns with the #ifdefs? (Edit: nevermind, I just remembered the original source had some particularly colorful language as I was getting frustrated with it! I should probably rewrite history there / squash the commits)