Qt Everywhere: WebAssembly and WebGL streaming

    Qt Everywhere - this is how Qt source archives are named. At 5.12.0, WebAssembly and WebGL streaming are delivered and everywhere sounds different. So I asked for something to prototype. A prototype chat on web sockets was quickly thrown in to test network support. Under the cut there will be an instruction for building and running a project on WebAssembly, an example of invoking JavaScript from C ++.


    Building Qt with WebAsse Assembly


    First you need to put the toolchain emscripten , which will collect Qt. Do not forget to write the environment variables that qmake would find emcc. The script was configurerun with the following parameters:


    ./configure \
     -prefix /home/dmitry/Qt/5.12.0/wasm \
     -xplatform wasm-emscripten  \
     -confirm-license -opensource \
     -nomake tests \
     -c++std c++1z \
     -nomake examples \
     -release \
     -no-dbus \
     -skip qtxmlpatterns \
     -skip qttools

    Further, as elsewhere:


    $ make 
    $ make install

    Build and run the project


    $ ~/Qt/5.12.0/wasm/bin/qmake 
    $ make
    $ emrun chat.html 

    Platform specific code


    Sewing the url on which the backend is hanging is not very good, because want to run on an arbitrary port. In the case of work from the browser, you need to take location.hostnameand location.portto determine where the backend is running. This will have a little pee on JavaScript.


    For fans of defines there Q_OS_WASM, I prefer to put the code in pimpl and separate files. Pimpl is superfluous here, but the code will be spread to different files


    Let's get some config


    //config.h#pragma once#include<QtCore/QUrl>classConfig
    {public:
        static QUrl wsUrl();
    };

    and two implementations


    //config.cpp#include<QtCore/QCoreApplication>#include<QtCore/QCommandLineParser>#include"config.h"
    QUrl Config::wsUrl()
    {
        QCommandLineParser parser;
        QCommandLineOption wsOption(QStringList() << "u" << "url"
                                    , "WebSocket url"
                                    , "url"
                                    , "ws://localhost:1234");
        parser.addOption(wsOption);
        parser.process(*QCoreApplication::instance());
        return QUrl(parser.value(wsOption));
    }

    //config_wasm.cpp#include<QtCore/QByteArray>#include<emscripten/emscripten.h>#include<emscripten/html5.h>#include"config.h"
    QUrl Config::wsUrl()
    {
        QByteArray buff(1024, 0);
        EM_ASM_({
           var url = "ws://"+ window.location.hostname + ":" + window.location.port + "/ws";
           stringToUTF8(url, $0, $1);
        }, buff.data(), buff.size());
        return QUrl(QString::fromUtf8(buff));
    }

    It remains to register in the pro file


    wasm {
    SOURCES += config_wasm.cpp
    } else {
    SOURCES += config.cpp
    }

    EM_ASM_This is the emscripten magic that allows you to call JavaScript code from C ++. Although it could be done without JavaScript


    emscripten::val location = emscripten::val::global("location");
    auto host = QString::fromStdString(location["host"].as<string>());
    auto protocol = QString::fromStdString(location["protocol"].as<string>());

    Browser support


    Desktop browsers: runs and works in Сhrome, Firefox, Safari, Edge (here it was necessary to enable the experimental functions of JavaScript). Depending on the hardware, there may be significant delays in compiling WebAssembly.


    In Chrome, Andorid can take minutes to compile WebAssembly. Immediately noticed the lack of support for mobile browsers, namely, there is no calling the system keyboard, when trying to enter text.


    Safari on iOS 12 here the application crashes at the WebAssembly compilation stage and I did not debug. Theoretically, you can go to asm.js, but this requires a separate study.


    Qt Quick WebGL


    The blog positioned as VNC on web sockets with rendering on WebGL. From Qt WebSockets and Qt dependencies compiled with OpenGL ES 2 support i. drive on hardware without a GPU will be painful. To support it, it is enough to put Qt WebGL Streaming Plugin in the online installer and run the application with the parameter -platform webglor -platform webgl:port=80, if you need to specify the port.


    But this technology has its limitations:


    • delays or notorious input lag;
    • There is no support for Qt Widgets;
    • lack of sound transmission;
    • one user connection per process i. In the second tab, no longer go, the preloader will spin.

    I also noticed a drop in fps during StackView animation on transitions between screens. The dignity of WebGL streaming:


    • built-in server;
    • minimum of effort. I did not have to compile from Qt sources and rebuild an existing application separately.

    Ways to use WebAssembly and WebGL Streaming


    Alternative to Wt when there is a ready application in C ++ and you need to fasten a web interface to it. For example web-interface to torrent rocking.


    Web interface for some smart home. Not for nothing in MQTT in Qt, and on msorvig / qt-webassembly-examples an example of mqtt_simpleclient . You can have a common UI code that works on the tablet and in the browser.


    The code is available on GitHub , prepared binaries in the same place


    Also popular now: