Spec-Zone.ru › Qt 5.12

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

С момента выпуска Qt 5.0, Qt больше не содержит собственной реализации системы окон (QWS). Для однопроцессных случаев использования абстракция платформы Qt является лучшим решением. Несколько графических процессов могут поддерживаться через Wayland.

Существует множество плагинов платформы, которые потенциально могут быть использованы на встраиваемых Linux-системах: EGLFS, LinuxFB, DirectFB, Wayland. Доступность этих плагинов зависит от конфигурации Qt. На многих платах eglfs выбирается в качестве значения по умолчанию. Если значение по умолчанию не подходит, параметр переменной окружения QT_QPA_PLATFORM может быть использован для запроса другого плагина. В качестве альтернативы, для быстрых тестов, можно использовать -platform команду с тем же синтаксисом.

Настройка конкретного устройства

Компиляция Qt для данного устройства требует инструментальной цепочки и sysroot. Кроме того, некоторые устройства требуют кода адаптации, специфичного для поставщика, для поддержки EGL и OpenGL ES 2.0. Это не относится к платформам без ускорения, например, к тем, которые используют плагин LinuxFB, который предназначен только для рендеринга на основе программного обеспечения.

Директория qtbase/mkspecs/devices содержит конфигурацию и код адаптации графики для ряда устройств. Например, mkspec linux-rasp-pi2-g++ содержит настройки сборки, такие как оптимальные флаги компилятора и линковщика для устройства Raspberry Pi 2. Mkspec также содержит информацию о реализации eglfs-хуков (код адаптации, специфичный для поставщика), или ссылку на подходящий плагин интеграции устройств eglfs. Устройство выбирается с помощью параметра -device инструмента конфигурации configure. Имя, которое следует после этого аргумента, должно хотя бы частично совпадать с одним из подкаталогов в директории devices.

Следующий пример конфигурации для Raspberry Pi 2. Для большинства встраиваемых Linux-платформ команда конфигурации выглядит аналогично:

./configure -release -opengl es2 -device linux-rasp-pi2-g++ -device-option CROSS_COMPILE=$TOOLCHAIN/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf- -sysroot $ROOTFS -prefix /usr/local/qt5

Самые важные параметры - -device и -sysroot. Указав -sysroot, файлы заголовков и библиотеки, используемые тестами обнаружения функций configure, а также Qt, берутся из указанного расположения, а не из стандартных расположений на хост-компьютере. Это означает, что установка пакетов разработки на хост-машине не имеет значения. Например, для получения поддержки libinput недостаточно или не нужно иметь заголовки и библиотеки разработки libinput установленные на хост-системе. Вместо этого заголовки и библиотеки для целевой архитектуры (например, ARM) должны присутствовать в sysroot.

pkg-config поддерживается также при выполнении кросс-компиляции. configure автоматически устанавливает PKG_CONFIG_LIBDIR для того, чтобы pkg-config отчитывался о настройках компилятора и линковщика, основанных на sysroot вместо хост-машины. Это обычно работает без дополнительных корректировок. Однако переменные окружения, такие как PKG_CONFIG_PATH, должны быть удалены с хост-машины перед запуском configure. В противном случае процесс сборки Qt может попытаться использовать неподходящие заголовки и библиотеки с хост-системы.

Указание -sysroot приводит к автоматической установке аргумента --sysroot при вызове компилятора. В некоторых случаях это нежелательно и может быть отключено, передав -no-gcc-sysroot в configure.

-prefix, -extprefix и -hostprefix управляют предполагаемой целевой директорией сборки Qt. В приведенном выше примере ожидается, что ARM-сборка Qt будет помещена в /usr/local/qt5 на целевом устройстве. Обратите внимание, что запуск make install ничего не развернёт на устройстве. Вместо этого шаг install нацелен на директорию, указанную параметром extprefix, которая по умолчанию равна sysroot + prefix, и, следовательно, является необязательной. Однако во многих случаях «загрязнение» sysroot нежелательно, и поэтому указание -extprefix становится важным. Наконец, -hostprefix позволяет отделить инструменты хоста, такие как qmake, rcc, uic, от библиотек для целевой системы. При указании таких инструментов они будут установлены в указанной директории вместо extprefix.

Для получения дополнительной информации см. Параметры конфигурации Qt.

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

EGLFS

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

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

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

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

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

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

  • QT_QPA_EGLFS_INTEGRATION - В дополнение к скомпилированным хукам, также можно предоставить адаптацию, специфичную для устройства или поставщика, в виде динамически загружаемых плагинов. Эта переменная среды навязывает определённый плагин. Например, установка значения eglfs_kms использует бэкенд KMS/DRM. Это опция только тогда, когда в device makespecs не были указаны статические или скомпилированные хуки. На практике, традиционные скомпилированные хуки редко используются, почти все бэкенды сейчас мигрированы в плагины. Device makespecs по-прежнему содержат соответствующую 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(). Это актуально только для бэкендов, использующих устаревшую подсистему fbdev Linux. Обычно, с интервалом обмена по умолчанию 1, Qt предполагает, что вызов eglSwapBuffers() заботится о vsync; если это не так (например, из-за проблем с драйверами), попробуйте установить QT_QPA_EGLFS_FORCEVSYNC на ненулевое значение.
  • QT_QPA_EGLFS_FORCE888 - При установке значения, размеры каналов цветов красный, зелёный и синий игнорируются при создании нового контекста, окна или внеэкранной поверхности. Вместо этого плагин запрашивает конфигурацию с 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 выводятся при создании нового контекста. Вместе с переменной QSG_INFO Qt Quick, это может предоставить полезную информацию для устранения неполадок, связанных с конфигурацией 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 с -v, чтобы включить подробный вывод, чтобы увидеть вызовы компилятора и компоновщика для каждого теста конфигурации.

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

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

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

LinuxFB

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

Начиная с Qt 5.9, также доступна поддержка буферов DRM «глупых» буферов, так как fbdev устарел в ядре Linux. Это должно быть запрошено путем установки переменной среды 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 evdev. Чтобы включить использование 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) не установлены, а основанная на libudev система обнаружения устройств Qt сообщает, что доступна хотя бы одна мышь. Когда поддержка 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 и т. д.; эти сообщения можно безопасно игнорировать.

Touch

Для некоторых резистивных сенсорных экранов с одним касанием может потребоваться вернуться к использованию tslib вместо использования протокола Linux multi-touch и устройств событий. Для современных сенсорных экранов это не требуется. Поддержка tslib может быть включена путём установки переменной окружения QT_QPA_EGLFS_TSLIB или QT_QPA_FB_TSLIB в 1. Для изменения устройства установите переменную окружения TSLIB_TSDEVICE или передайте имя устройства в командной строке. Обратите внимание, что обработчик ввода tslib генерирует события мыши и поддерживает только одно касание, в отличие от evdevtouch, который также генерирует истинные многосенсорные события 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, widthxheight, widthxheight@vrefresh или строка модолинии.

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

Все экраны, сообщённые слоем 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, чтобы указать размеры в миллиметрах.

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

Каждый активный элемент массива 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 каждое из этих окон получит свою собственную выделенную нить отрисовки. Это хорошо, потому что нити можно регулировать независимо, основываясь на синхронизации с частотой обновления экрана, и они не будут мешать друг другу. С циклом 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(). За обеспечение этого отвечают конфигурация и приложение.

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

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

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

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

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

Используйте обычное окно, такое как подкласс 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 может использоваться с двумя разными DRM-API: legacy и atomic. Основное преимущество DRM-API атомарного типа заключается в возможности выполнения нескольких обновлений планов DRM в одном цикле обработки отрисовки, в то время как API legacy потребует одного обновления плана на одну синхронизацию с частотой обновления экрана.

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

Использование буфера кадра меньшего размера, чем разрешение экрана, также может быть полезным. Это возможно с использованием атомарного DRM, используя параметр 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 в системах, где доступно несколько бекендов ввода, установите переменную среды 1 в QT_QPA_EGLFS_NO_LIBINPUT.

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 МБ видеопамяти графического процессора. Для систем, не имеющих фиксированного объёма памяти, резервированной для графического процессора, это не проблема.

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 для встраиваемой Linux-системы.

Примечание: 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.

Примечание: У вас могут возникнуть проблемы с вводом сенсорного экрана при использовании эталонного композитора Weston. Дополнительную информацию см. на странице Вики Qt.

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

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

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

Spec-Zone.ru

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