Embedded

Работа без X11/Wayland: eglfs и linuxfb платформенные плагины

Введение

Большинство embedded-устройств не запускают полноценную систему рабочих столов с X11 или Wayland — Qt-приложение часто является единственным графическим приложением на устройстве, рисующим прямо в фреймбуфер или напрямую через EGL без промежуточного оконного менеджера. В статье разберём платформенные плагины Qt, спроектированные именно для таких сценариев — eglfs (для устройств с поддержкой OpenGL ES через EGL) и linuxfb (для устройств без аппаратного ускорения графики вовсе, рисующих напрямую в Linux framebuffer).

Концепция

Платформенный плагин Qt (QPA, Qt Platform Abstraction) определяет, как Qt взаимодействует с нижележащей графической системой — на десктопе это обычно xcb (X11) или wayland, а для embedded без полноценной оконной системы — eglfs или linuxfb. eglfs даёт полноэкранное Qt-приложение, использующее аппаратное ускорение GPU через EGL/OpenGL ES напрямую, без посредничества оконного менеджера — это обеспечивает максимальную производительность для embedded-устройств с GPU. linuxfb — более простой, программный рендеринг прямо в буфер кадра Linux без использования GPU вовсе, подходящий для устройств без графического ускорителя или для совсем простых интерфейсов.

Пример кода: Работа без X11/Wayland

# Запуск приложения с явным указанием платформенного плагина eglfs
./EmbeddedDashboard -platform eglfs

# Альтернатива через переменную окружения (удобно для systemd-сервисов)
export QT_QPA_PLATFORM=eglfs
./EmbeddedDashboard

# linuxfb — для устройств без GPU, с указанием конкретного устройства фреймбуфера
./EmbeddedDashboard -platform linuxfb:fb=/dev/fb0
# /etc/systemd/system/embedded-dashboard.service —
# типичный способ автозапуска Qt-приложения как единственного "композитора" на устройстве

[Unit]
Description=Embedded Dashboard Qt Application
After=multi-user.target

[Service]
Environment=QT_QPA_PLATFORM=eglfs
Environment=QT_QPA_EGLFS_INTEGRATION=eglfs_kms  # для устройств без X/Wayland, прямой доступ к DRM/KMS
ExecStart=/opt/embedded-dashboard/EmbeddedDashboard
Restart=always
User=root

[Install]
WantedBy=multi-user.target
// main.cpp — определение фактически используемого платформенного плагина в коде,
// полезно для условной логики, специфичной для embedded-режима без оконной системы
#include <QGuiApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    const QString platformName = QGuiApplication::platformName();
    qDebug() << "Используемый платформенный плагин:" << platformName;

    if (platformName == "eglfs" || platformName == "linuxfb") {
        qDebug() << "Запуск в embedded-режиме без оконной системы — "
                  "приложение является единственным на экране устройства";
        // здесь может быть логика, специфичная для полноэкранного embedded-режима,
        // например, отключение возможности свернуть/переместить окно
    }

    return app.exec();
}

Пояснения к коду

Запуск через -platform eglfs (или эквивалентную переменную окружения QT_QPA_PLATFORM) переключает Qt на работу без оконного менеджера — приложение становится единственным, занимающим весь экран устройства, что характерно для большинства embedded-сценариев (киоски, бортовые дисплеи, панели управления оборудованием). QT_QPA_EGLFS_INTEGRATION=eglfs_kms — пример дополнительной переменной окружения, конкретизирующей, как именно eglfs взаимодействует с графическим железом — kms (Kernel Mode Setting) означает прямой доступ к DRM-подсистеме ядра Linux, без устаревшего и менее предсказуемого пути через старые механизмы настройки видеорежима.

Пример systemd-юнита показывает типичный способ автозапуска embedded Qt-приложения сразу при загрузке устройства, без интерактивного входа пользователя — Restart=always гарантирует, что приложение, единственное отображаемое на устройстве, автоматически перезапустится при неожиданном завершении, что критично для embedded-устройств, где нет пользователя, способного вручную перезапустить приложение. Проверка QGuiApplication::platformName() в коде приложения позволяет логике приложения адаптироваться в зависимости от того, запущено ли оно в полноценной десктопной оконной системе (для отладки на машине разработчика) или в «голом» embedded-режиме без оконного менеджера.

Подводные камни

  • Попытка использовать eglfs на устройстве без правильно настроенного DRM/KMS драйвера или без соответствующих прав доступа (/dev/dri/* устройств) приводит к ошибкам инициализации графики при запуске — для нового, ещё не до конца настроенного embedded-окружения это частая первая проблема, требующая проверки корректности видеодрайвера ядра Linux на конкретной плате до попытки запуска Qt-приложения.
  • Несколько процессов, одновременно пытающихся захватить eglfs/прямой доступ к DRM-устройству. В отличие от X11/Wayland, спроектированных для множества одновременно работающих графических клиентов, eglfs ожидает единственного «владельца» экрана — попытка запустить второй Qt-процесс с eglfs одновременно с уже работающим первым обычно завершается ошибкой захвата устройства, а не корректным совместным использованием экрана.
  • Использование linuxfb для современных, графически насыщенных QML-интерфейсов с анимациями. Поскольку linuxfb не использует GPU вовсе, весь рендеринг выполняется программно на CPU — для сложного, анимированного QML-интерфейса это может быть значительно медленнее, чем ожидается, и linuxfb лучше подходит для простых, статичных или редко обновляемых интерфейсов на устройствах без графического ускорителя вообще.
  • Отсутствие тестирования отрисовки и обработки ввода (touch/мышь) специфично для конкретной комбинации платформенного плагина и используемого железа. Поведение обработки сенсорного ввода через eglfs зависит от правильной настройки соответствующих input-плагинов Qt (evdevtouch и аналогичных), и без явной их настройки сенсорный экран может не работать вовсе, даже если визуальный рендеринг через eglfs функционирует корректно — калибровка и настройка сенсорного ввода разбираются отдельно в следующей статье цикла.