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

habr.png

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 

class Config
{
public:

    static QUrl wsUrl();

};

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

//config.cpp
#include 
#include 
#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 

#include 
#include 

#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());
auto protocol = QString::fromStdString(location["protocol"].as());


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

Десктопные браузеры: запускается и работает в С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, подготовленные бинарники там же

© Habrahabr.ru