Qt Everywhere: WebAssembly и WebGL стриминг

    Qt Everywhere — так именуются архивы с исходниками Qt. В 5.12.0 завезут WebAssembly и WebGL стриминг и everywhere звучит уже по другому. Так и просилось что-нибудь запрототипировать. Был быстро накидан прототип чатика на веб-сокетах, что бы протестировать поддержку сети. Под катом будет инструкция по сборке и запуска проекта на WebAssembly, пример вызова JavaScript из С++.


    Сборка Qt с WebAssembly


    Сперва нужно поставить toolchain emscripten, которым будем собирать Qt. Не забудьте прописать переменные окружения, что бы qmake нашел emcc. Скрипт configure запускался со следующими параметрами:


    ./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

    Дальше как и везде:


    $ make 
    $ make install

    Сборка и запуск проекта


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

    Платформенно-зависимый код


    Зашивать url на котором висит бэкенд не очень хорошо, т.к. захочется запускать на произвольном порту. В случает работы из браузера нужно взять location.hostname и location.port что бы определить где запущен бэкенд. Для этого придется немного пописать на JavaScript.


    Для любителей дефайнов есть Q_OS_WASM, я же предпочитаю выносить код в pimpl и отдельные файлы. Pimpl здесь лишний, но код разнесу на разные файлы


    Заведем какой-нибудь конфиг


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

    и две реализации


    //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));
    }

    Осталось прописать в pro файле


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

    EM_ASM_ это магия emscripten позволяющая вызывать JavaScript код из C++. Хотя можно это было сделать и без JavaScript


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

    Поддержка в браузерах


    Десктопные браузеры: запускается и работает в Сhrome, Firefox, Safari, Edge(тут пришлось включить экспериментальные функции JavaScript). В зависимости от железа могут быть существенные задержки на компиляции WebAssembly.


    В Chrome на Andorid могут пройти минуты на компиляцию WebAssembly. Сразу заметил отсутствия поддержки мобильных браузеров, а именно нет вызова системной клавиатуры, при попытки ввести текст.


    Safari на iOS 12 тут приложение падает на этапе компиляции WebAssembly и я не стал дебажить. Теоретически можно перейти на asm.js, но это требует отдельного исследования.


    Qt Quick WebGL


    В блоге позиционировался как VNC на веб-сокетах с отрисовкой на WebGL. Из зависимостей Qt WebSockets и Qt собранный с поддержкой OpenGL ES 2 т.е. гонять на железе без GPU будет мучительно. Для её поддержки достаточно поставить Qt WebGL Streaming Plugin в онлайн установщике и запустить приложение с параметром -platform webgl или -platform webgl:port=80, если нужно указать порт.


    Но у этой технологии есть свои ограничения:


    • задержки или пресловутый input lag;
    • отсутствует поддержка приложений на Qt Widgets;
    • отсутствие передачи звука;
    • одно пользовательское соединение на процесс т.е. во второй вкладке уже не зайти, будет крутиться прелоадер.

    Так же я заметил проседание fps при анимации StackView на переходах между экранами. Достоинство WebGL стриминга:


    • встроенный сервер;
    • минимум усилий. Мне не пришлось собирать из исходников Qt и отдельно пересобирать существующее приложение.

    Способы применения WebAssembly и WebGL Streaming


    Альтернатива Wt когда есть готовое приложение на C++ и к нему нужно прикрутить веб-интерфейс. Например web-интерфейс к torrent качалке.


    Web интерфейс для какого-нибудь умного дома. Не даром в Qt завезли MQTT, а на msorvig/qt-webassembly-examples пример mqtt_simpleclient. Можно иметь общий код UI который работает на планшете и в браузере.


    Код доступен на GitHub, подготовленные бинарники там же

    Поддержать автора
    Поделиться публикацией

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 10

      +1
      Вся эта история с WebAssembly напоминает фрактал…
        0
        Так фракталы они же красивые. В следующий раз попробую добавить ложку дегтя и поэксплуатировать какую-нибудь багу.
          0
          Может цикл статей по WebAssembly — простой вывод в консоль, работа с DOM, стилями, обработка графики, потоки, сеть, камера, микрофон? =)
            0
            А что не так с графикой в Qt? А сеть тут есть. Манипуляция с DOM нужна тогда, когда пишется кастомный контрол. Например webview, который на десктопе использует Qt WebEngine, а в браузере iframe. Следующая будет по отладке.
              0
              Сколько весит результирующий бинарник?
                0
                Сам chat.wasm 21Mb, в gzip'e 7.1 Mb. Демка Go + UI 28Mb.
        0
        хорошо если Qt действительно будет «everywhere», и мы получим fullstack framework для любых (не сильно специализированных) задач
          0
          Только не хватает примеров использования в продакшене.
          0

          Спасибо за wasm {...} в .pro и Q_OS_WASM в define-ах! В документации этого нет.

            0
            Интересно, как оно в плане написание видеоплееров

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое