Spec-Zone.ru › Qt 5.13

Qt для встраиваемых Linux-систем

На встраиваемых Linux-системах можно использовать несколько плагинов платформы: EGLFS, LinuxFB, DirectFB или Wayland. Однако доступность этих плагинов зависит от того, как настроено Qt.

Плагин EGLFS является стандартным для многих плат. Если он не подходит, используйте переменную среды QT_QPA_PLATFORM, чтобы запросить другой плагин. В качестве альтернативы, для быстрых тестов, используйте аргумент командной строки -platform с тем же синтаксисом.

Примечание: Начиная с Qt 5.0, Qt больше не имеет собственной реализации системы окон (QWS). Для однопроцессорных случаев Qt Platform Abstraction — это лучшее решение; многопроцессорные случаи поддерживаются через Wayland.

Плагины платформы для встраиваемых Linux-устройств

EGLFS

EGL — это интерфейс между OpenGL и собственной системой окон. Qt может использовать EGL для управления контекстом и поверхностями, однако API не содержит специфики платформы. Создание родного окна, которое не обязательно будет реальным окном на экране, всё равно должно выполняться с помощью средств, специфичных для платформы. Вот почему нам нужен код адаптации, специфичный для платы или графического процессора. Обычно эти адаптации предоставляются как:

  • Вставки EGLFS — один файл исходного кода, скомпилированный в плагин платформы
  • Интеграция устройства EGL — динамически загружаемые плагины

EGLFS — это плагин платформы для запуска приложений Qt5 поверх EGL и OpenGL ES 2.0 без собственной системы окон, такой как X11 или Wayland. В дополнение к Qt Quick 2 и приложениям на основе OpenGL, EGLFS поддерживает окна с программной отрисовкой, такие как QWidget. Для QWidget содержимое виджетов отрисовывается процессором в изображения, которые затем загружаются в текстуры и компонуются плагином.

EGLFS является рекомендуемым плагином для современных встраиваемых Linux-устройств, которые включают графический процессор.

EGLFS заставляет первое окно верхнего уровня — либо QWidget, либо QQuickView — стать полноэкранным. Это окно также выбирается в качестве корневого окна виджетов, в которое компонуются все другие виджеты верхнего уровня. Например, диалоговые окна, всплывающие меню или комбинированные поля. Это поведение необходимо, потому что с EGLFS всегда существует ровно одно родное окно и одна поверхность окна EGL; они принадлежат виджету или окну, которое создаётся первым. Этот подход хорошо работает, когда существует главное окно, которое существует на протяжении всего времени жизни приложения, а все остальные виджеты являются либо не верхнего уровня, либо создаются позже, после отображения главного окна.

Существуют дополнительные ограничения для окон на основе OpenGL. EGLFS поддерживает одно полноэкранное окно GL (начиная с Qt 5.3), например, окно OpenGL-based QWindow, QQuickView или QOpenGLWidget. Открытие дополнительных окон OpenGL или смешивание таких окон с содержимым на основе QWidget не поддерживается; Qt завершает приложение с сообщением об ошибке.

При необходимости eglfs можно настроить с помощью следующих переменных среды:

Переменная среды Описание
QT_QPA_EGLFS_INTEGRATION Помимо скомпилированных вставок, также возможно использование динамически загружаемых плагинов для предоставления адаптации, специфичной для устройства или поставщика. Эта переменная среды навязывает определённый плагин. Например, установление значения eglfs_kms использует бэкэнд KMS/DRM. Это возможно только тогда, когда в спецификациях устройства не были указаны статические или скомпилированные вставки. На практике традиционные скомпилированные вставки редко используются, почти все бэкэнды теперь мигрировали в плагины. В спецификациях устройства всё ещё присутствует соответствующая EGLFS_DEVICE_INTEGRATION запись: имя предпочтительного бэкэнда для конкретного устройства. Это необязательно, но очень полезно, чтобы избежать необходимости устанавливать эту переменную среды, если в целевой системе присутствует более одного плагина. В настольной среде бэкэнды KMS или X11 имеют приоритет, в зависимости от наличия переменной среды DISPLAY.

Примечание: На некоторых платах используется специальное значение none вместо фактического плагина. Это указывает на то, что никакая специальная интеграция не требуется для использования EGL с буфером отображения; плагины загружать не нужно.

QT_QPA_EGLFS_PHYSICAL_WIDTH и QT_QPA_EGLFS_PHYSICAL_HEIGHT Указывают ширину и высоту физического экрана в миллиметрах. На платформах, где значение нельзя получить из устройства буфера отображения /dev/fb0 или другими способами, используется значение DPI по умолчанию 100. Используйте эту переменную для переопределения любых таких значений по умолчанию. Установка этой переменной важна, потому что приложения на основе QWidget или Qt Quick Controls полагаются на эти значения. Запуск таких приложений с жёстко заданными настройками может привести к тому, что элементы пользовательского интерфейса будут иметь размеры, не подходящие для используемого дисплея.
QT_QPA_EGLFS_ROTATION Указывает поворот, применяемый к содержимому с программной отрисовкой в приложениях на основе QWidget. Поддерживаемые значения составляют 180, 90 и -90. Эта переменная не применяется к окнам на основе OpenGL, включая Qt Quick. Приложения Qt Quick могут применять преобразования в сцене QML вместо этого. Стандартный eglfs курсор мыши всегда учитывает это значение, отображая соответствующий перемещённый и повернутый указатель, независимо от типа приложения. Однако особые реализации курсора, такие как аппаратный курсор бэкэнда KMS/DRM, могут не поддерживать поворот.
QT_QPA_EGLFS_FORCEVSYNC При установке eglfs запрашивает FBIO_WAITFORVSYNC на устройстве буфера отображения после каждого вызова eglSwapBuffers(). Эта переменная актуальна только для бэкэндов, использующих устаревшую подсистему Linux fbdev. Обычно, при стандартном интервале переключения 1, Qt предполагает, что вызов eglSwapBuffers() заботится о vsync; если это не так (например, из-за ошибок драйвера), попробуйте установить QT_QPA_EGLFS_FORCEVSYNC на ненулевое значение.
QT_QPA_EGLFS_FORCE888 При установке eglfs игнорирует размер каналов цвета красного, зелёного и синего при создании нового контекста, окна или внеэкранной поверхности. Вместо этого плагин запрашивает конфигурацию с 8 битами на канал. Это может быть полезно на устройствах, где конфигурации с менее чем 32 или 24 битами на пиксель (например, 5-6-5 или 4-4-4) выбираются по умолчанию, несмотря на то, что они не являются идеальными, например, из-за эффектов полос. Вместо изменения кода приложения эта переменная предоставляет способ принудительного использования конфигураций 24 или 32 бит на пиксель.

Кроме того, доступны следующие менее часто используемые переменные:

Переменная среды Описание
QT_QPA_EGLFS_FB Переопределяет устройство буфера отображения. По умолчанию /dev/fb0. На большинстве встраиваемых платформ эта переменная не очень важна, потому что буфер отображения используется только для получения настроек, таких как размеры дисплея. Однако на некоторых устройствах эта переменная позволяет указать, какой дисплей использовать в нескольких конфигурациях дисплеев, подобно параметру fb в LinuxFB.
QT_QPA_EGLFS_WIDTH и QT_QPA_EGLFS_HEIGHT Содержат ширину и высоту экрана в пикселях. Хотя eglfs пытается определить размеры из устройства буфера отображения /dev/fb0, это не всегда работает. Может потребоваться вручную указать размеры.
QT_QPA_EGLFS_DEPTH Переопределяет глубину цвета для экрана. На платформах, где устройство буфера отображения /dev/fb0 недоступно или запрос не удаётся, используется значение по умолчанию 32. Используйте эту переменную для переопределения таких значений по умолчанию.

Примечание: Эта переменная влияет только на значение глубины цвета, сообщаемое QScreen. Она не связана с конфигурациями EGL и глубиной цвета, используемой для рендеринга OpenGL.

QT_QPA_EGLFS_SWAPINTERVAL По умолчанию запрашивается интервал переключения 1. Эта переменная позволяет синхронизировать работу с вертикальной частотой обновления дисплея. Используйте эту переменную для переопределения значения интервала переключения. Например, передача 0 отключает блокировку при переключении, что приводит к работе с максимальной скоростью без синхронизации.
QT_QPA_EGLFS_DEBUG При установке выводятся некоторые отладочные данные. Например, входной QSurfaceFormat и свойства выбранной конфигурации EGL выводятся при создании нового контекста. При использовании вместе с переменной Qt Quick QSG_INFO вы можете получить полезную информацию для решения проблем, связанных с конфигурацией EGL.

В дополнение к QT_QPA_EGLFS_DEBUG, eglfs также поддерживает современную систему категорированного логирования Qt. Доступны следующие категории логирования:

  • qt.qpa.egldeviceintegration — Включает логирование для динамически загружаемых бэкэндов. Используйте эту категорию для проверки, какой бэкэнд используется.
  • qt.qpa.input — Включает вывод отладочных данных как от обработчиков ввода evdev и libinput. Используйте эту категорию для проверки, было ли распознано и открыто заданное устройство ввода.
  • qt.qpa.eglfs.kms — Включает подробное логирование в бэкэнде KMS/DRM.

После выполнения configure, убедитесь, что просмотрели его вывод. Это самый простой и быстрый способ определить, включены ли необходимый бэкэнд EGLFS, libudev или libinput. Короче говоря, если в выводе configure есть нежелательное "нет", выполните:

./configure -v

чтобы включить подробный вывод, чтобы вы могли увидеть вызовы компилятора и линковщика для каждого теста конфигурации.

Примечание: Если вы столкнулись с ошибками о недостающих заголовках, библиотеках или кажущихся непонятными ошибках линковщика, часто это признак неполного или повреждённого sysroot и не связано с Qt.

Например, при нацеливании на Raspberry Pi с собственными графическими драйверами Broadcom вывод должен содержать что-то вроде следующего:

QPA backends:
EGLFS ................................ yes
EGLFS details:
  EGLFS i.Mx6 ........................ no
  EGLFS i.Mx6 Wayland ................ no
  EGLFS EGLDevice .................... no
  EGLFS GBM .......................... no
  EGLFS Mali ......................... no
  EGLFS Rasberry Pi .................. yes
  EGL on X11 ......................... no

Если это не так, не рекомендуется продолжать сборку, так как ускоренная графика не будет функциональной без бэкэнда, специфичного для Raspberry Pi, даже если остальная часть Qt успешно скомпилируется.

LinuxFB

Этот плагин записывает данные напрямую в буфер отображения через подсистему fbdev Linux. Поддерживается только программная отрисовка. Обратите внимание, что в некоторых конфигурациях производительность дисплея может быть ограниченной.

Однако, поскольку fbdev устаревает в ядре Linux, поддержка буферов отображения DRM также доступна начиная с Qt 5.9. Чтобы использовать её, установите переменную среды QT_QPA_FB_DRM в ненулевое значение. При установке, при условии, что буферы отображения поддерживаются вашей системой, к устаревшим устройствам фреймбуфера, таким как /dev/fb0, доступ не будет осуществляться. Вместо этого, отрисовка настраивается через API DRM, аналогично бэкенду eglfs_kms в EGLFS. Вывод является двойным буферизованным и переключаемым страницами, предоставляя надлежащий vsync для отрисованного программным обеспечением контента.

Примечание: Когда используются буферы отображения, ни один из описанных ниже параметров не применим, поскольку свойства, такие как физические и логические размеры экрана, запрашиваются автоматически.

Плагин linuxfb позволяет указать дополнительные параметры через переменную среды QT_QPA_PLATFORM или параметр командной строки -platform. Например, QT_QPA_PLATFORM=linuxfb:fb=/dev/fb1 указывает, что устройство фреймбуфера /dev/fb1 должно быть использовано вместо стандартного fb0. Для указания нескольких параметров разделяйте их двоеточием (:).

Настройки Описание
fb=/dev/fbN Указывает устройства фреймбуфера. В многодисплейных системах эта настройка позволяет запускать приложение на различных дисплеях. В настоящее время нет способа использовать несколько фреймбуферов из одного приложения Qt.
size=<width>x<height> Указывает размер экрана в пикселях. Плагин пытается запросить размеры дисплея, как физические, так и логические, из устройства фреймбуфера. Однако этот запрос не всегда приводит к корректным результатам; может потребоваться явно указать значения.
mmsize=<width>x<height> Указывает физическую ширину и высоту в миллиметрах.
offset=<width>x<height> Указывает смещение верхнего левого угла экрана в пикселях. По умолчанию положение находится в (0, 0).
nographicsmodeswitch Указывает, что не следует переключать виртуальный терминал в графический режим (KD_GRAPHICS). Обычно, включение графического режима отключает мигание курсора и выключение экрана. Однако, когда этот параметр установлен, эти две функции также пропускаются.
tty=/dev/ttyN Переопределяет виртуальную консоль. Используется только когда nographicsmodeswitch не установлено.

Начиная с Qt 5.9, поведение EGLFS и LinuxFB было синхронизировано относительно политики изменения размера окна: первое окно верхнего уровня принудительно занимает весь экран в обоих платформах плагинах. Если этого не требуется, установите переменную среды QT_QPA_FB_FORCE_FULLSCREEN в значение 0, чтобы восстановить поведение предыдущих версий Qt.

Вход

При отсутствии системы оконного менеджера, ввод мыши, клавиатуры и сенсорного экрана считывается напрямую через evdev или с помощью вспомогательных библиотек, таких как libinput или tslib. Обратите внимание, что это требует, чтобы узлы устройств /dev/input/event* были доступны для чтения пользователем. eglfs и linuxfb содержат весь код обработки ввода.

Использование libinput

libinput - это библиотека для обработки устройств ввода. Она предлагает альтернативу собственной поддержке ввода Qt. Чтобы включить использование libinput, убедитесь, что файлы разработки для libudev и libinput доступны при конфигурации и построении Qt. xkbcommon также необходимо, если нужна поддержка клавиатуры. С eglfs и linuxfb дальнейших действий не требуется, так как эти плагины по умолчанию используют libinput. Если поддержка libinput недоступна или переменная среды QT_QPA_EGLFS_NO_LIBINPUT установлена, применяются собственные обработчики evdev Qt.

Ввод на eglfs и linuxfb без libinput

Параметры, такие как имя узла устройства, могут быть установлены в переменных среды QT_QPA_EVDEV_MOUSE_PARAMETERS, QT_QPA_EVDEV_KEYBOARD_PARAMETERS и QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS. Разделяйте записи двоеточием. Эти параметры действуют как альтернатива передаче настроек в параметре командной строки -plugin, и в некоторых бэкендах они являются необходимыми: eglfs и linuxfb используют встроенные обработчики ввода, поэтому отдельный параметр -plugin не используется.

Кроме того, встроенные обработчики ввода могут быть отключены, установив QT_QPA_EGLFS_DISABLE_INPUT или QT_QPA_FB_DISABLE_INPUT в 1.

Мышь

Курсор мыши отображается всякий раз, когда QT_QPA_EGLFS_HIDECURSOR (для eglfs) или QT_QPA_FB_HIDECURSOR (для linuxfb) не заданы, а обнаружение устройств Qt на основе libudev сообщает, что доступна хотя бы одна мышь. Когда поддержка libudev отсутствует, курсор мыши всегда отображается, если явно не отключен через переменную среды.

Поддержка горячей замены поддерживается, но только если Qt был сконфигурирован с поддержкой libudev (то есть, если заголовки разработки libudev присутствуют в sysroot во время конфигурации). Это позволяет подключать или отключать устройство ввода во время работы приложения.

Обработчик мыши evdev поддерживает следующие дополнительные параметры:

  • /dev/input/... - Указывает имя устройства ввода. Если не указано, Qt ищет подходящее устройство либо через libudev, либо проходя по доступным узлам.
  • nocompress - По умолчанию события ввода, которые не приводят к изменению позиции по сравнению с последним событием мыши Qt, сжимаются; новое событие мыши Qt отправляется только после изменения позиции или состояния кнопки. Это можно отключить, установив параметр nocompress.
  • dejitter - Указывает предел джиттера. По умолчанию джиттеринг отключен.
  • grab - Если 1, Qt захватит устройство для эксклюзивного использования.
  • abs - Некоторые сенсорные экраны передают абсолютные координаты и не могут быть отличимы от тачпадов. В этой особой ситуации передайте abs, чтобы указать, что устройство использует абсолютные события.

Клавиатура

Обработчик клавиатуры evdev поддерживает следующие дополнительные параметры:

  • /dev/input/... - Указывает имя устройства ввода. Если не указано, Qt ищет подходящее устройство либо через libudev, либо проходя по доступным узлам.
  • grab - Включает захват устройства ввода.
  • keymap - Указывает имя файла пользовательской карты клавиатуры.
  • enable-compose - Включает композитинг.
  • repeat-delay - Устанавливает пользовательскую задержку повтора клавиши.
  • repeat-rate - Устанавливает пользовательскую скорость повтора клавиши.

В системах Embedded Linux, которые не имеют отключённых сессий терминала, поведение при нажатии клавиши может быть запутанным, так как событие ввода обрабатывается приложением Qt и tty. Для решения этой проблемы доступны следующие варианты:

  • EGLFS и LinuxFB пытаются отключить клавиатуру терминала при запуске приложения, установив режим клавиатуры tty в K_OFF. Это предотвращает попадание нажатий клавиш на терминал. Если стандартное поведение необходимо восстановить по какой-либо причине, установите переменную среды QT_QPA_ENABLE_TERMINAL_KEYBOARD в 1. Обратите внимание, что это работает только при запуске приложения из удалённой консоли (например, через ssh) и ввод с клавиатуры терминала остаётся включённым.
  • Альтернативный подход заключается в использовании параметра evdev обработчика клавиатуры grab, передав grab=1 в QT_QPA_EVDEV_KEYBOARD_PARAMETERS. В результате происходит попытка захвата устройства ввода. Если захват grab успешен, никакие другие компоненты системы не получают события от него, пока запущено приложение Qt. Этот подход более подходит для приложений, запущенных удалённо, так как ему не нужен доступ к устройству tty.
  • Наконец, для многих специализированных образов Embedded Linux не имеет смысла включать стандартные сессии терминала в первую очередь. Обратитесь к документации вашей среды разработки, чтобы узнать, как их отключить. Например, при создании образов с помощью Yocto Project, сброс SYSVINIT_ENABLED_GETTYS приводит к отсутствию процесса getty, а значит, и ввода на любом виртуальном терминале.

Если стандартная встроенная карта клавиатуры недостаточна, можно указать другую, либо через параметр keymap, либо с помощью специфичной для eglfs функции loadKeymap(). Последнее позволяет изменять карту клавиатуры во время выполнения. Однако обратите внимание, что это требует использования встроенного обработчика клавиатуры eglfs; он не поддерживается, когда обработчик клавиатуры загружается через параметр командной строки -plugin.

Примечание: Специальные системные комбинации клавиш, такие как переключение консолей (Ctrl+Alt+Fx) или удаление (Ctrl+Alt+Backspace), в настоящее время не поддерживаются и игнорируются.

Для создания пользовательской карты клавиатуры можно использовать утилиту kmap2qmap. Она находится в модуле qttools. Исходные файлы должны быть в стандартном формате Linux kmap, который понимается командой ядра loadkeys. Это означает, что можно использовать следующие источники для создания файлов qmap:

  • Проект Linux Console Tools (LCT).
  • Карты клавиатуры X11 Xorg могут быть преобразованы в формат kmap с помощью утилиты ckbcomp.
  • Так как файлы kmap - это текстовые файлы, их также можно создать вручную.

kmap2qmap - это командная программа, которая требует как минимум 2 файла в качестве параметров. Последний - сгенерированный файл .qmap, а все остальные анализируются как входные файлы .kmap. Например:

kmap2qmap i386/qwertz/de-latin1-nodeadkeys.kmap include/compose.latin1.inc de-latin1-nodeadkeys.qmap

Примечание: kmap2qmap не поддерживает все (псевдо)символы, которые поддерживает ядро Linux. При преобразовании стандартной карты клавиатуры будет показано несколько предупреждений, касающихся Show_Registers, Hex_A и т. д.; эти сообщения можно безопасно игнорировать.

Донсенсорный экран

Для некоторых резистивных сенсорных экранов с одноточечным касанием может потребоваться вернуться к использованию tslib вместо использования протокола Linux multi-touch и устройств событий. Для современных сенсорных экранов это не требуется. tslib поддержка может быть включена, установив переменную окружения QT_QPA_EGLFS_TSLIB или QT_QPA_FB_TSLIB в значение 1. Чтобы изменить устройство, установите переменную окружения TSLIB_TSDEVICE или передайте имя устройства в командной строке. Обратите внимание, что обработчик ввода tslib генерирует события мыши и поддерживает только одно касание, в отличие от evdevtouch, который также генерирует истинные события multi-touch QTouchEvent.

Обработчик касаний evdev поддерживает следующие дополнительные параметры:

  • /dev/input/... — Указывает имя входного устройства. Если параметр не указан, Qt ищет подходящее устройство либо через libudev, либо путем обхода доступных узлов.
  • rotate — На некоторых сенсорных экранах координаты необходимо повернуть, что делается путём установки значения rotate в 90, 180 или 270.
  • invertx и inverty — Для инвертирования координат X или Y в событиях ввода передайте значения invertx или inverty.

Например, выполнение export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event5:rotate=180 перед запуском приложений приводит к явно указанному сенсорному устройству и перевороту координат — полезно, когда ориентация фактического экрана и сенсорного экрана не совпадает.

Планшеты с ручкой

Плагин evdevtablet предоставляет базовую поддержку планшетов с ручкой Wacom и аналогичных устройств. Он генерирует только события QTabletEvent. Для его активации передайте значение QT_QPA_GENERIC_PLUGINS=evdevtablet в переменной окружения или, альтернативно, в качестве аргумента -plugin evdevtablet в командной строке. Плагин может принимать параметр узла устройства, например QT_QPA_GENERIC_PLUGINS=evdevtablet:/dev/event1, в случае если автоматическое обнаружение устройств Qt (основанное на libudev или обходе /dev/input/event*) не работает корректно.

Отладка устройств ввода

Возможна печать информации в вывод отладки, включив правило ведения журнала qt.qpa.input, например, установив переменную окружения QT_LOGGING_RULES в значение qt.qpa.input=true. Это полезно для определения используемого устройства или для устранения проблем с обнаружением устройств.

Использование пользовательских изображений курсора мыши

eglfs поставляется со своим набором изображений курсора мыши размером 32x32. Если этих изображений недостаточно, пользовательский атлас курсоров может быть предоставлен путём установки переменной окружения QT_QPA_EGLFS_CURSOR в имя файла JSON. Файл также можно встроить в приложение с помощью системы ресурсов Qt.

Например, встраиваемый атлас курсоров с 8 изображениями курсоров в строке может быть указан следующим образом:

{
  "image": ":/cursor-atlas.png",
  "cursorsPerRow": 8,
  "hotSpots": [
      [7, 2],
      [12, 3],
      [12, 12],
      ...
  ]
}

Обратите внимание, что изображения предполагаются плотно упакованными в атласе: ширина и высота курсоров определяются на основе общего размера изображения и значения cursorsPerRow. Атласы должны предоставлять изображение для всех поддерживаемых курсоров.

Вывод на дисплей

При подключении нескольких дисплеев уровень поддержки нацеливания на один или несколько из них из одного приложения Qt варьируется между платформ-плагинами и часто зависит от устройства и его графической подсистемы.

eglfs с eglfs_kms бэкендом

При использовании бэкенда KMS/DRM, eglfs сообщает обо всех доступных экранах в QGuiApplication::screens(). Приложения могут нацеливаться на разные экраны с разными окнами через QWindow::setScreen().

Примечание: Ограничение одного полноэкранного окна на экран всё ещё действует. Изменение экранов после отображения QWindow также не поддерживается. Поэтому важно, чтобы встраиваемые приложения выполняли все необходимые вызовы QWindow::setScreen() перед вызовом QWindow::show().

При начальном разработке на заданном встраиваемом устройстве часто необходимо проверить поведение устройства и драйверов, а также убедиться, что подключенные дисплеи работают должным образом. Один из простых способов — использовать пример hellowindow. Запуск его с аргументами -platform eglfs --multiscreen --timeout отобразит вращающийся логотип Qt на каждом подключенном экране в течение нескольких секунд.

Примечание: Большинство параметров конфигурации, описанных ниже, применимы ко всем бэкендам, основанным на KMS/DRM, независимо от технологии управления буферами (GBM или EGLStreams).

Бэкенд KMS/DRM также поддерживает пользовательские конфигурации через файл JSON. Установите переменную окружения QT_QPA_EGLFS_KMS_CONFIG в имя файла, чтобы включить эту возможность. Файл также можно встроить в приложение с помощью системы ресурсов Qt. Пример конфигурации приведен ниже:

{
  "device": "/dev/dri/card1",
  "hwcursor": false,
  "pbuffers": true,
  "outputs": [
    {
      "name": "VGA1",
      "mode": "off"
    },
    {
      "name": "HDMI1",
      "mode": "1024x768"
    }
  ]
}

Здесь мы настраиваем указанное устройство, чтобы

  • он не использовал аппаратный курсор (возвращается к отрисовке курсора мыши через OpenGL; по умолчанию аппаратные курсоры включены, так как они более эффективны),
  • он будет использовать QOffscreenSurface со стандартными поверхностями EGL pbuffer (по умолчанию это отключено, и вместо этого используется поверхность gbm),
  • вывод на VGA-разъём отключён, в то время как HDMI активен с разрешением 1024x768.

Кроме того, такая конфигурация также отключает поиск устройства через libudev и вместо этого используется указанное устройство.

Когда mode не определено, выбирается режим, который система сообщает как предпочтительный. Допустимые значения для mode — off, current, preferred, skip, widthxheight, widthxheight@vrefresh или строка модема.

Указание current выберет режим с разрешением, соответствующим текущему. Из-за того, что переключение режимов выполняется только тогда, когда желаемый режим отличается от активного (если не принудительно установлено через переменную окружения QT_QPA_EGLFS_ALWAYS_SET_MODE), это значение полезно для сохранения текущего режима и любого содержимого в плоскостях, не затронутых Qt. skip игнорирует подключение к выходу, как если бы оно было отключено. off аналогично, но также изменяет режим, чтобы отключить дисплей.

Все экраны, сообщённые слоем DRM, по умолчанию будут обрабатываться как один большой виртуальный рабочий стол. Реализация курсора мыши учтёт это и будет перемещаться по экранам, как ожидается. Хотя не рекомендуется, режим виртуального рабочего стола может быть отключён, установив separateScreens в значение false в конфигурации, если это необходимо.

По умолчанию виртуальный рабочий стол формируется слева направо, в соответствии с порядком подключений, как сообщается системой. Это можно изменить, установив virtualIndex в значение, начиная с 0. Например, следующая конфигурация использует предпочтительное разрешение, но гарантирует, что левая сторона виртуального рабочего стола — экран, подключенный к HDMI-порту, а правая — к DisplayPort:

{
  "device": "drm-nvdc",
  "outputs": [
    {
      "name": "HDMI1",
      "virtualIndex": 0
    },
    {
      "name": "DP1",
      "virtualIndex": 1
    }
  ]
}

Порядок элементов в массиве не имеет значения. Выходы с неопределёнными виртуальными индексами будут размещены после других, при сохранении исходного порядка в списке подключений DRM.

Для создания вертикального рабочего пространства (то есть, для упорядочивания сверху вниз вместо слева направо) добавьте свойство virtualDesktopLayout после device со значением vertical.

Примечание: Рекомендуется, чтобы все экраны в виртуальном рабочем столе имели одинаковое разрешение, иначе элементы, такие как курсор мыши, могут вести себя неожиданным образом при входе в области, существующие только на одном конкретном экране.

Если virtualIndex недостаточно, можно использовать свойство virtualPos для явного указания верхнего левого положения интересуемого экрана. Возьмём предыдущий пример и предположим разрешение 1080p для HDMI1, следующая строка помещает второй HDMI-экран под первым:

{
   ...
  "outputs": [
    ...
    {
      "name": "HDMI2",
      "virtualPos": "0, 1080"
    }
  ]
}

Примечание: Избегайте таких конфигураций, когда требуется поддержка мыши. Поведение курсора мыши может быть непредсказуемым при нелинейных макетах. Однако касания не должны вызывать проблем.

В некоторых случаях автоматическое получение размера физического экрана через DRM может завершиться ошибкой. Обычно переменные окружения QT_QPA_EGLFS_PHYSICAL_WIDTH и QT_QPA_EGLFS_PHYSICAL_HEIGHT использовались для предоставления недостающих значений, но это больше не подходит при наличии нескольких экранов. Вместо этого используйте свойства physicalWidth и physicalHeight в списке outputs для указания размеров в миллиметрах.

Примечание: Разные физические размеры, а следовательно, разные логические разрешения экрана, не рекомендуются, поскольку это может привести к непредвиденным проблемам из-за того, что некоторые компоненты графического стека могут не знать о нескольких экранах и полагаться только на значения первого экрана.

Каждый активный выход из массива outputs соответствует одному экземпляру QScreen, сообщённому функцией QGuiApplication::screens(). Основной экран, возвращаемый функцией QGuiApplication::primaryScreen(), по умолчанию — это экран, зарегистрированный первым. Если не используется virtualIndex, это означает, что решение основано на порядке подключений DRM. Чтобы переопределить это, установите свойство primary в значение true для нужного элемента в списке outputs. Например, чтобы гарантировать, что экран, соответствующий VGA-выводу, будет основным даже в том случае, если система сообщает о HDMI-экране первым, можно сделать следующее:

{
  "device": "/dev/dri/card0",
  "outputs": [
      { "name": "HDMI1" },
      { "name": "VGA1", "mode": "1280x720", "primary": true },
      { "name": "LVDS1", "mode": "off" }
  ]
}

Для отладки может быть полезно включить логирование отладки бэкенда KMS/DRM. Для этого включите правило ведения журнала, qt.qpa.eglfs.kms.

Примечание: Встраиваемой среде виртуальные рабочие столы ограничены по сравнению с полной системой окон. Окна, перекрывающие несколько экранов, окна, не являющиеся полноэкранными, и перемещение окон между экранами следует избегать, и они могут работать не так, как ожидается.

Наиболее распространённый и наилучшим образом поддерживаемый сценарий использования многоэкранной настройки — открытие отдельного QQuickWindow или QQuickView для каждого экрана. При стандартном цикле рендеринга threaded дерева сцен Qt Quick, каждое из этих окон получит свою собственную отдельную нить рендеринга. Это хорошо, так как нити могут быть ограничены по скорости в отдельности, на основе vsync, и не будут влиять друг на друга. С циклом basic это может стать проблематичным, и в результате анимации могут ухудшиться.

В качестве примера обнаружения всех подключенных экранов и создания QQuickView для каждого из них можно сделать так:

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

    QVector<QQuickView *> views;
    for (QScreen *screen : app.screens()) {
        QQuickView *view = new QQuickView;
        view->setScreen(screen);
        view->setResizeMode(QQuickView::SizeRootObjectToView);
        view->setSource(QUrl("qrc:/main.qml"));
        QObject::connect(view->engine(), &QQmlEngine::quit, qGuiApp, &QCoreApplication::quit);
        views.append(view);
        view->showFullScreen();
    }

    int result = app.exec();

    qDeleteAll(views);
    return result;
}

Расширенные возможности eglfs_kms

Клонирование экранов (отображение) поддерживается начиная с Qt 5.11. Его можно включить свойством clones:

{
  "device": "/dev/dri/card0",
  "outputs": [
      { "name": "HDMI1", "mode": "1920x1080" },
      { "name": "DP1", "mode": "1920x1080", "clones": "HDMI1" }
 ]
}

Здесь содержимое на дисплее, подключенном через DisplayPort, будет таким же, как и на HDMI. Это обеспечивается просто путем вывода одного и того же буфера на оба.

Примечание: Это может работать только в том случае, если разрешения одинаковы, нет несовместимостей в формате принятых буферов и приложение не имеет вывода на экран QScreen, связанный с клонируемым местом назначения. На практике это означает, что ни один окно QWindow, связанный с экранным QScreen — DP1 в примере — не должен выполнять операцию QOpenGLContext::swapBuffers(). За обеспечение этого отвечают конфигурация и приложение.

Режим без графического интерфейса пользователя (headless) через узлы рендеринга DRM поддерживается начиная с Qt 5.11. Это позволяет выполнять вычисления на графическом процессоре (OpenGL compute shaders, OpenCL) или рендеринг OpenGL вне экрана без необходимости привилегий DRM master. В этом режиме приложения могут работать даже тогда, когда другой процесс уже выводит что-либо на экран.

Простое переключение device с /dev/dri/card0 на /dev/dri/renderD128 бесполезно само по себе, так как ряд операций не может выполняться в режиме без графического интерфейса пользователя. Поэтому это необходимо комбинировать со свойством headless, например:

{
    "device": "/dev/dri/renderD128",
    "headless": "1024x768"
}

Помните, что окна по-прежнему масштабируются для соответствия размеру экрана — теперь виртуальному, — поэтому необходимо указать размер в свойстве headless. Также отсутствует регулировка частоты кадров на основе vsync.

После включения приложения имеют два типичных варианта для выполнения рендеринга вне экрана в режиме без графического интерфейса пользователя:

Использование обычного окна, например, подкласса QOpenGLWindow, нацеленного на буфер кадра по умолчанию окна, что означает gbm_surface на практике:

MyOpenGLWindow w;
w.show(); // will not actually show up on screen
w.grabFramebuffer().save("output.png");

Или типичный подход вне экрана с дополнительным FBO:

QOffscreenSurface s;
s.setFormat(ctx.format());
s.create();
ctx.makeCurrent(&s);
QOpenGLFramebufferObject fbo(1024, 768);
fbo.bind();
ctx.functions()->glClearColor(1, 0, 0, 1);
ctx.functions()->glClear(GL_COLOR_BUFFER_BIT);
fbo.toImage().save("output.png");
ctx.doneCurrent();

KMS/DRM могут использоваться с двумя различными API DRM: legacy и atomic. Основное преимущество API DRM atomic заключается в возможности нескольких обновлений плоскостей DRM в одном цикле рендеринга, в то время как API legacy потребовало бы одно обновление плоскости на один кадр vsync.

API atomic полезен, когда приложение нуждается в смешивании контента в наложениях, сохраняя все обновления в одном кадре vsync. Тем не менее, не все устройства поддерживают этот API, и он может быть недоступен на некоторых старых устройствах. Бекенд KMS по умолчанию использует API legacy, но вы можете включить API DRM atomic, установив переменную окружения QT_QPA_EGLFS_KMS_ATOMIC в значение 1.

Использование буфера кадра меньшего размера, чем разрешение экрана, также может быть полезным. Это возможно с помощью DRM atomic, используя параметр size в файле JSON. В примере ниже используется буфер кадра 1280x720 на видеорежиме 3840x2160:

{
  "device": "/dev/dri/card0",
  "outputs": [
    { "name": "HDMI1", "mode": "3840x2160", "size": "1280x720", "format": "argb8888" }
  ]
}

eglfs с бэкендом eglfs_kms_egldevice

Этот бэкенд, обычно используемый на устройствах Tegra, аналогичен бэкенду KMS/DRM, описанному выше, за исключением того, что он полагается на расширения EGLDevice и EGLStream вместо GBM.

Для технических подробностей об этом подходе ознакомьтесь с данной презентацией.

Начиная с Qt 5.7, этот бэкенд разделяет много внутренней реализации с бэкендом на основе GBM. Это означает, что поддерживаются несколько экранов и расширенная конфигурация с помощью QT_QPA_EGLFS_KMS_CONFIG. Однако некоторые настройки, такие как hwcursor и pbuffers, неприменимы.

По умолчанию бэкенд автоматически выбирает правильный EGL-слой для плоскости вывода по умолчанию. При необходимости это можно переопределить, установив переменную окружения QT_QPA_EGLFS_LAYER_INDEX в индекс желаемого слоя. Этот подход в настоящее время не поддерживает несколько выходов, поэтому его использование следует ограничить системами с одним экраном. Чтобы увидеть доступные слои и отладить возможные проблемы при запуске, включите категорию логов qt.qpa.eglfs.kms.

В некоторых случаях может потребоваться установка видеорежима при запуске приложения, даже если экран сообщает, что нужное разрешение уже установлено. Обычно это оптимизируется, но если экран остается выключенным, попробуйте установить переменную окружения QT_QPA_EGLFS_ALWAYS_SET_MODE в ненулевое значение и перезапустить приложение.

Для настройки поведения объекта EGLStream, используемого бэкендом, используйте переменную окружения QT_QPA_EGLFS_STREAM_FIFO_LENGTH. Предполагается, что KHR_stream_fifo поддерживается целевой системой. По умолчанию поток работает в режиме почтового ящика. Чтобы переключиться на режим FIFO, установите значение 1 или больше. Значение определяет максимальное количество кадров, которое может содержать поток.

В некоторых системах может потребоваться нацеливание на определённую плоскость наложения через предварительно определенный соединитель. Простое принудительное задание индекса слоя с помощью QT_QPA_EGLFS_LAYER_INDEX не выполняет настройку плоскости и, следовательно, само по себе непригодно. Вместо этого в таких особых случаях используйте переменные окружения QT_QPA_EGLFS_KMS_CONNECTOR_INDEX и QT_QPA_EGLFS_KMS_PLANE_INDEX. При установке этих переменных будет использоваться только указанный соединитель и плоскость, все остальные выходы будут игнорироваться. Бэкенд позаботится о выборе EGL-слоя, соответствующего требуемой плоскости, и о конфигурации плоскости.

Ввод касания в системах с несколькими экранами на KMS/DRM

Для сенсорных экранов в системах с несколькими дисплеями требуется дополнительное внимание, так как события касания должны быть маршрутизированы к правильному виртуальному экрану, и это требует правильного соответствия между сенсорными экранами и выходами дисплея.

Сопоставление выполняется с помощью файла конфигурации JSON, указанного в QT_QPA_EGLFS_KMS_CONFIG и описанного в предыдущих разделах. При наличии свойства touchDevice в элементе массива outputs, значение обрабатывается как узел устройства, а сенсорное устройство связывается с соответствующим выходом дисплея.

Например, предположим, что наш сенсорный экран имеет узел устройства /dev/input/event5 и является сенсорным экраном, интегрированным в монитор, подключённый через HDMI как вторичный экран. Следующая конфигурация обеспечивает правильный перевод событий касания (и синтезированных событий мыши):

 {
    "device": "drm-nvdc",
    "outputs": [
      {
        "name": "HDMI1",
        "touchDevice": "/dev/input/event5",
        "virtualIndex": 1
      },
      {
        "name": "DP1",
        "virtualIndex": 0
      }
    ]
}

Примечание: В случае сомнений включите протоколирование как для графических, так и для системных подсистем ввода, установив переменную окружения QT_LOGGING_RULES=qt.qpa.*=true перед запуском приложения. Это поможет определить правильные узлы устройств ввода и может раскрыть проблемы конфигурации вывода, которые в противном случае трудно отладить.

Примечание: Начиная с Qt 5.8, вышеуказанное поддерживается только для бэкенда ввода evdevtouch. Другие варианты, такие как на основе libinput, по-прежнему будут маршрутизировать события на основной экран. Для принудительного использования evdevtouch в системах, где доступно несколько бэкэндов ввода, установите переменную окружения QT_QPA_EGLFS_NO_LIBINPUT в 1.

eglfs с другими бэкендами

Другие бэкэнды, которые обычно основаны на целевом буфере кадра или API композиции напрямую через реализацию EGL поставщика, обычно обеспечивают ограниченную или никакую поддержку нескольких дисплеев. На платах i.MX6 с графическими процессорами Vivante переменная окружения QT_QPA_EGLFS_FB может использоваться для указания буфера кадра, аналогично linuxfb. На Raspberry Pi переменная окружения QT_QPA_EGLFS_DISPMANX_ID может использоваться для указания экрана для вывода. Значение соответствует одному из констант DISPMANX_ID_, см. документацию Dispmanx. Обратите внимание, что эти подходы, в отличие от KMS/DRM, обычно не позволят выводить на несколько экранов из одного приложения. В качестве альтернативы могут также быть доступны переменные окружения или параметры ядра, специфичные для драйвера, для управления используемым буфером кадра. Обратитесь к документации встроенной платы.

Видеопамять

Системы с фиксированным объёмом выделенной видеопамяти могут потребовать дополнительных мер предосторожности перед запуском приложения Qt, основанного на Qt Quick или классах, таких как QOpenGLWidget. Значение по умолчанию может быть недостаточным для таких приложений, особенно при отображении на экране высокого разрешения (например, Full HD). В этом случае они могут начать работать непредсказуемо. Рекомендуется обеспечить наличие как минимум 128 МБ видеопамяти GPU. Для систем, не имеющих фиксированного объема памяти, резервируемой для GPU, это не проблема.

linuxfb

Используйте параметр плагина fb для указания устройства буфера кадра.

Обработчики сигналов Unix

Плагины консольных платформ, такие как eglfs и linuxfb, по умолчанию устанавливают обработчики сигналов для захвата прерываний (SIGINT), приостановки и продолжения (SIGTSTP, SIGCONT) и завершения (SIGTERM). Таким образом, клавиатура, курсор терминала и, возможно, другие состояния графики могут быть восстановлены при завершении или приостановке приложения из-за kill, Ctrl+C или Ctrl+Z. (хотя завершение или приостановку через клавиатуру возможно только при установке QT_QPA_ENABLE_TERMINAL_KEYBOARD, как описано выше в разделе «Ввод»). Однако в некоторых случаях захват SIGINT может быть нежелательным, поскольку он может конфликтовать, например, с удаленной отладкой. Поэтому предоставляется переменная окружения QT_QPA_NO_SIGNAL_HANDLER для отказа от всех встроенных обработчиков сигналов.

Шрифты

Qt обычно использует fontconfig для доступа к системным шрифтам. Если fontconfig недоступен, Qt перейдет к использованию QBasicFontDatabase. В этом случае приложения Qt будут искать шрифты в каталоге Qt lib/fonts. Qt автоматически обнаружит предварительно отрисованные шрифты и шрифты TrueType. Этот каталог может быть переопределён установкой переменной окружения QT_QPA_FONTDIR.

Дополнительную информацию о поддерживаемых форматах см. в разделе Qt for Embedded Linux Fonts.

Примечание: Qt больше не поставляет шрифты в каталоге lib/fonts. Это означает, что платформа (образ системы) должна обеспечивать необходимые шрифты.

Плагины платформы для систем окон на встраиваемых устройствах Linux

XCB

Это плагин X11, используемый на обычных платформах Linux для настольных компьютеров. В некоторых встроенных средах, которые предоставляют X и необходимые файлы разработки для xcb, этот плагин работает так же, как и на обычном настольном компьютере.

Примечание: На некоторых устройствах нет поддержки EGL и OpenGL в X, поскольку реализация EGL несовместима с Xlib. В этом случае плагин XCB строится без поддержки EGL, что означает, что приложения Qt Quick 2 или другие приложения на основе OpenGL не работают с этим плагином платформы. Однако его можно использовать для запуска приложений с программным рендерингом (например, на основе QWidget).

Как правило, использование XCB на встроенных устройствах не рекомендуется. Плагины, такие как eglfs, вероятно, обеспечат лучшую производительность и ускорение аппаратного обеспечения.

Wayland

Wayland — это лёгкая система окон; или точнее, это протокол для взаимодействия клиентов с сервером отображения.

Qt Wayland предоставляет плагин платформы wayland, который позволяет приложениям Qt подключаться к композитору Wayland.

Для получения более подробной информации см. Wayland и Qt.

Примечание: Возможны проблемы с вводом сенсорного экрана при использовании эталонного композитора Weston. Для получения дополнительной информации см. https://wiki.qt.io/WestonTouchScreenIssues.

Связанные темы

  • Qt для создания устройств
  • Настройка устройства встраиваемой Linux
  • Эмулятор
  • Виртуальная клавиатура Qt
  • Qt Quick WebGL

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.13/embedded-linux.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API