[Development] Qt for WebAssembly status update

Tor Arne Vestbø Tor.arne.Vestbo at qt.io
Thu Jun 6 13:48:11 CEST 2024


Nice overview, thanks Morten!

Tor Arne

On 6 Jun 2024, at 13:20, Morten Sørvig via Development <development at qt-project.org> wrote:

Hello all,

It’s been a while since the previous update so I figured it was time for a small “state of the union” on the WebAssembly port.

I’ll focus on topics which are most relevant to development of Qt itslef - all of the problematic parts that we should spend time on. Rest assured many things work already and it possible to build Qt applications for the platform :) Feel free to ask questions if there’s anything that should be discussed in more detail.

On to the list:

* Static and dynamic linking.

Static linking is the default, we are currently investigating dynamic linking.

It is expected that static linking will be default configuration for some time to come, where dynamic linking can be beneficial in special cases such as delayed loading of Qt libraries or sharing libraries between multiple applications (developing with shared libraries is also quite convenient since you can do incremental rebuilds)

Using dynamic linking currently requires patching Emscripten, and it does not work well with the asyncify feature (and earlier also not with threads, but that is looking better now)

* Thread support

Thread support is now stable (has been from some time), also with installer/binary packages. Emscripten implements pthreads on top of Web Workers. See https://emscripten.org/docs/porting/pthreads.html

Some issues remain:

- Threads require SharedArrayBuffer, which require putting the web page into cross-origin isolated mode, which places restrictions on cross-origin resource fetching.

- Blocking the main thread may deadlock, if the main thread is waiting for a pthread whose web worker has not been crated yet. This may require porting code, or pre-allocating threads with the PTHREAD_POOL_SIZE linker flag.

For these reasons we plan on keeping the no-thread mode supported going forwrad.

* exec() and asyncify

The web platform does not support blocking the main thread (not at all - pthread mutex is implemented using a spin-lock), and also does not provide a select()-style API which can wait for events. This makes implementing exec() and QEventLoop::WaitForMoreEvents difficult.

For QApplication::exec() we have a hack - exec() never returns and leaks the contents of the stack at the point when it’s called. This makes sure the root applications objects stay alive for the lifetime of the application. We also support a workaround: allocate on the heap in main(), don’t call exec(), and return early (see Emscripten EXIT_RUNTIME).

Long term, WebAssembly stack switching (https://github.com/WebAssembly/stack-switching) should make implementing exec() possible. In the shorter term we are utilizing Emscripten’s asyncify feature for this.

Asyncify comes in two versions:

- Asyncify 1: Supported on all browsers, but does not quite scale to Qt-sized software (increased build time, code size, CPU usage)

- JSPI (aka Asyncify 2): Supported on Chrome, behind a flag. No scaling issues.

So the current support situation here is not quite satisfactory. In addition we have also recently identified that we need to rework/improve the asyncify support in Qt. At the moment, porting away from using exec() might be the best option (Qt Quick apps generally don’t call exec() and should be fine here).

* Exceptions

Exceptions are disabled by default. Qt supports enabling native wasm exceptions using the  -feature-wasm-exceptions configure flag. Enabling exceptions breaks the QApplication::exec() hack, so we don’t enable it by default. (it’s also an optional part of the wasm spec, but supported by all mayor browsers).

Qt does not use exceptions so the non-support is OK in that regard, however we are using 3rdparty libraries which depend on exceptions (spirv-cross, assimp), which are causing issues.

* SIMD

Off by default, can be enabled at configure time with -wasm-simd-128. That allows the compiler to use SIMD instructions for loop auto-vectorization etc, but there are currently no wasm simd code paths in Qt. (Should we add more portable SIMD code paths to Qt? Using e.g. portable simd intrinsics/Highway/std::experimental::simd).

* Graphics

We are targeting WebGL 2 / OpenGL ES 3, and also support WebGL 1 / OpenGL ES 2 for simple Qt Quick  “2D UI” use cases. All major browsers support WebGL 2; devices which don’t are maybe not a good target for Qt for WebAssembly.

WebGPU is interesting as a next step. The current high-level known issues are:

   - shader translation: spirv-cross does not support WGSL. The way forward is most likely to use a library like Tint here, but we don’t know if that covers all use cases required by Qt.
   - async: WebGPU is async in a couple of places where Qt is sync (from memory it is the GPU.requestAdapter() / GPUAdapter: requestDevice() initialization functions).

* Auto tests

We are continuing to port and enable auto tests. In some ways porting the tests is harder than porting Qt itself, since they have lots of sync code (block and wait for window visible etc) - the tests are run with asyncify enabled for this reason. We also have a small set of platform-specific tests.

We are currently using the auto-test batching feature to work around the scaling limitations of asyncify. Switching over to running the tests on Chrome/JSPI instead might be done at some point in the future.


That concludes the overview of the current state for Qt’s youngest (?)  platform plugin  - thanks for reading.

- Morten


















--
Development mailing list
Development at qt-project.org
https://lists.qt-project.org/listinfo/development

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20240606/096de931/attachment-0001.htm>


More information about the Development mailing list