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@qt-project.org
https://lists.qt-project.org/listinfo/development

Reply via email to