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

web: Build two WASM modules, with/without extensions, load the appropriate one #5834

Merged
merged 3 commits into from
Jan 12, 2022

Conversation

torokati44
Copy link
Member

@torokati44 torokati44 commented Dec 10, 2021

This includes, "unblocks", and extends #5225.

Also adds dynamic fallback to an additional, non-extension-enabled WebAssembly module, mostly for compatibility with poor Safari.

The simd128 extension is not yet directly utilized by us (it possibly is by some dependencies), but I have a few ideas where to use it, improving video decoding performance significantly.
EDIT: The simd128 feature should help a lot with the color conversion of both H.263 and VP6 videos since ruffle-rs/h263-rs#15 got merged. The IDCT in the H.263 decoder could also potentially benefit from it with some tweaking, but I haven't found/made any speedups there yet.

This also roughly (but not quite) doubles both the time it takes to build the web version, and the size of all web-based release packages.

What I don't like is that completely blanking out RUSTFLAGS also disables the web_sys_unstable_apis config option, which is needed for WebGPU.
We could just brush over this, saying that if browser compatibility is the entire reason for this fallback module, then surely WebGPU is not important. (Even though, Safari does have experimental support for it.)

EDIT: RUSTFLAGS is now set locally and properly for both modules, always setting the web_sys_unstable_apis config option.

@torokati44
Copy link
Member Author

torokati44 commented Dec 10, 2021

If someone more experienced in TS finds a way to avoid having to upgrade to es2022 and enabling the topLevelAwait experiment, please let me know!

EDIT: The topLevelAwait experiment is no longer needed, and the upgrade is only to es2020 now! Thanks a lot, TypeScript Discord! ☺️

@torokati44
Copy link
Member Author

torokati44 commented Dec 10, 2021

As this also negatively affects CI times makes CI fail, it would be nice if this dual-module machinery could be easily disabled.
Then it could even be off by default perhaps, only enabled for the releases.
Just where to put this switch and how to make it work well?

EDIT: CI is now fixed, so maybe turning it off is not that critical.
EDIT: Only a single module is built now by default, both for development an CI, with a copy of it standing in for the other one as well.

@torokati44
Copy link
Member Author

I'm thinking about adding a custom cargo profile for either (or both) of the wasm builds, to not jeopardize the build cache every time. Although that's a fairly new feature. And for frequent builds during development, using sccache is advisable anyway.
What do you think?

@Herschel
Copy link
Member

Herschel commented Dec 15, 2021

My opinion is that anything in Rust stable is fair game, so I think it's worth giving the custom profiles a try!

@torokati44
Copy link
Member Author

It looks like until the linked cargo issue is addressed, we're going to be stuck with setting the different RUSTFLAGS in package.json... :/
Not really tragic, but not that neat either...

@torokati44
Copy link
Member Author

torokati44 commented Dec 17, 2021

Okay, I think I made up my mind about this for now.
As is now, the first config is all-in (at least with the 4 relevant extensions), and the fallback is pure vanilla.
This way, Chrome and Firefox users get the full benefits of their choice, while the other build is guaranteed to keep working everywhere it did until now. Safari users are not benefited in any way (not even on 15.2, because of SIMD), but they are not worse off either. (And of course, as a general rule, only Apple can know what's best for them, I surely don't.)

Later, we could raise the bar on the fallback module as well, starting with extensions that worked on Safari 14.1 already (which is just signExtensions, if it matters), then maybe continuing with those that came in with Safari 15 (so, bulkMemory and saturatedFloatToInt).

If you disagree, I'm all ears. Well, of course, I am, even if you agree...

EDIT: I also just confirmed that passing --enable-sign-ext --enable-nontrapping-float-to-int --enable-simd --enable-bulk-memory to wasm-opt as well has no influence on the output whatsoever.

@torokati44
Copy link
Member Author

Does any NPM or shell scripting whiz perhaps have any tips on how we could skip building the vanilla .wasm module on CI, while keeping cross-shell compatibility? :/
It should just quietly not run any of the ...-noext commands if the CI envvar is set.

@danielhjacobs
Copy link
Contributor

danielhjacobs commented Dec 21, 2021

You could try prepending the ...-noext commands with [[ -z $CI ]] &&

See https://stackoverflow.com/questions/39619956/short-way-to-run-command-if-variable-is-set, and test it yourself.

[[ -z $USERNAME ]] && echo "Not defined" should print nothing on linux, but [[ -z $USERNAM ]] && echo "Not defined" should print "Not defined" (unless you set USERNAM).

@torokati44
Copy link
Member Author

I don't think this works in CMD.EXE as well... :/ That's the hard part. But thanks anyway!

@torokati44 torokati44 force-pushed the dual-wasm branch 5 times, most recently from b593677 to 6737f70 Compare December 22, 2021 00:49
@danielhjacobs
Copy link
Contributor

danielhjacobs commented Dec 22, 2021

This works on any system with Python:

python -c "import os, sys;sys.exit(1) if 'CI' in os.environ else sys.exit(0)" && echo 'a'

But needing to install python for CI may be asking a bit much...

@torokati44
Copy link
Member Author

A Node equivalent of this did come up... But I tried to find a simpler solution.

@torokati44 torokati44 force-pushed the dual-wasm branch 6 times, most recently from 5904768 to dd00bc8 Compare January 9, 2022 22:03
@torokati44
Copy link
Member Author

Okay, I think I resolved all comments that I could, and brought it again to a presentable state.
So, this is ready for the next round!

@@ -268,7 +268,7 @@ jobs:
shell: bash -l {0}
run: |
npm run bootstrap
npm run build
npm run build:full-release
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite petty, but maybe rename this to build:full?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not sure about this one... Feels less descriptive to me, while I'm not seeing how it's any better. What do you think, @adrian17?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I lean towards build:release. I understand and somewhat agree with shortening this, but build:release seems to match better with build:debug. As in "this is the debug version. this is the release version". Maybe wait for an opinion from Adrian too though. Calling this the full version, as you mention, feels less descriptive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW:
image

So, I am fine with build:release as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but build:release seems to match better with build:debug
As in "this is the debug version. this is the release version".

This is my reasoning:
The issue is that these days, "release" means "optimized", not "this is what we use to release the software".

For comparison, these are (very general) build configurations for Firefox:

  • max debug, unoptimized; you basically never want to actually run this
  • normal optimized build (what cargo or Visual Studio would call "release")
  • increasingly fancy configurations with LTO, PGO, branding etc - for actual software release or more thorough tests and benchmarks

And these more or less correspond to our configurations:

  • max debug, unoptimized; you basically never want to actually run this
  • optimized (current npm run build)
  • optimized with extra debug info/avm tracing (current npm run build:debug)
  • increasingly fancy configurations with special wasm features

Now, when a dev comes and wants to build it, they most likely want "normal optimized build". But for a Rust programmer, this would probably be cargo run --release. But if they apply this logic here and run build:release, they get "final-release" and not "development-release" :) Which is why I'd prefer to reserve some more explicit wording for "this is max optimized, not for everyday development".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That isn't perfect either: Even for the plain build command now, -O is passed to rustc and wasm-opt is also called on the output either way... :|

Yeah, I realized that and deleted my comment suggesting build:optimized. Maybe build:fully-featured, but if the purpose of renaming is to shorten the command, that sort of defeats the purpose.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose yet another variant: build:dual-wasm :| - This one doesn't have release it.
And build:dual-wasm-release is way too long again?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@relrelb Could you please elaborate on what you had against build:full-release originally?

Anyway, what do you and @danielhjacobs think about build:dual-wasm?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with dual-wasm

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong preference to any name (this is a classical example for bikeshedding), I just thought build:full is a little more concise and descriptive name. I'm fine with staying on build:full-release, changing to build:dual-wasm, or even changing to something else.

@torokati44 torokati44 force-pushed the dual-wasm branch 3 times, most recently from 6cecc2f to 7696479 Compare January 11, 2022 22:26
@torokati44
Copy link
Member Author

torokati44 commented Jan 11, 2022

I get the feeling that the only thing holding this up now is the name of that script. And I am not sure how to resolve this distributed decision, with all options having pros and cons brought up by different contributors. Which is awkward.
Honestly, just having this finally in is more important to me now than this single final detail.
And I don't even know who should have the final say in this bikeshedesque question.

web/package.json Outdated Show resolved Hide resolved
…for the other

And enable the module that really uses WebAssembly extensions for the
releases by running the new "npm run build:dual-wasm" command, which
sets the ENABLE_WASM_EXTENSIONS=true environment variable.
@torokati44
Copy link
Member Author

So, if nobody has anything against npm run build:dual-wasm (vs. npm run build:full-release earlier, or any other option that came up), I think this is ready ... again! :D

Copy link
Contributor

@relrelb relrelb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Contributor

@relrelb relrelb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Member

@Herschel Herschel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do it! Thank you!

@Herschel Herschel merged commit db6731b into ruffle-rs:master Jan 12, 2022
@torokati44
Copy link
Member Author

Woooh yeah, thanks a whole hecking bunch and a half to everyone involved! 🥳

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