Qt для встроенной Linux-системы
С момента выпуска Qt 5.0, Qt больше не содержит собственной реализации системы окон (QWS). Для однопроцессорных случаев использования Абстракция платформы Qt является лучшим решением. Поддержка нескольких графических процессов возможна через Wayland.
Существует несколько плагинов платформы, которые потенциально могут быть использованы в системах Embedded Linux: EGLFS, LinuxFB, DirectFB, Wayland. Доступность этих плагинов зависит от конфигурации Qt. На многих устройствах eglfs выбран по умолчанию. Если значение по умолчанию не подходит, можно использовать переменную среды QT_QPA_PLATFORM, чтобы запросить другой плагин. В качестве альтернативы, для быстрых тестов можно использовать -platform команду с тем же синтаксисом.
Настройка конкретного устройства
Компиляция Qt для конкретного устройства требует инструментария и корневой системы. Кроме того, некоторые устройства требуют адаптации кода, специфичного для поставщика, для поддержки 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. Для большинства устройств Embedded 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, и поэтому является необязательным. Однако во многих случаях «загрязнение» корневой системы нежелательно, поэтому указание -extprefix становится важным. Наконец, -hostprefix позволяет отделять инструменты хоста, такие как qmake, rcc, uic, от библиотек для целевой системы. В случае его указания такие инструменты будут установлены в указанном каталоге вместо extprefix.
Дополнительную информацию см. в разделе Параметры конфигурации Qt.
Плагины платформы для устройств Embedded Linux
EGLFS
EGL — интерфейс между OpenGL и собственной системой окон. Qt может использовать EGL для управления контекстом и поверхностями, однако API не содержит информации о конкретной платформе: создание нативного окна (которое не обязательно будет фактическим окном на экране) по-прежнему должно выполняться с помощью средств, специфичных для платформы. Отсюда и необходимость кода адаптации, специфичного для платы или графического процессора. Такие адаптации предоставляются либо в виде eglfs-хуков, которые могут быть одним исходным файлом, скомпилированным в плагин платформы, либо в виде динамически загружаемых плагинов интеграции устройства EGL.
EGLFS — плагин платформы для запуска приложений Qt5 поверх EGL и OpenGL ES 2.0 без реальной системы окон (например, X11 или Wayland). Помимо Qt Quick 2 и приложений нативных OpenGL, он также поддерживает окна с рендерингом на основе программного обеспечения (например, QWidget). В последнем случае содержимое виджетов рендерится процессором в изображения, которые затем загружаются в текстуры и композируются плагином.
Это рекомендуемый плагин для современных устройств Embedded 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. Это вариант только тогда, когда в mkspec устройства не указаны статические или встроенные хуки. На практике традиционные встроенные хуки редко используются, почти все бэкэнды теперь мигрированы в плагины. mkspec устройства по-прежнему содержит соответствующую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(). Это актуально только для бэкэндов, использующих устаревшую подсистемуfbdevLinux. Обычно, при интервале переключения по умолчанию 1, Qt предполагает, что вызов eglSwapBuffers() обрабатывает vsync; если это не так (например, из-за ошибок драйвера), попробуйте установитьQT_QPA_EGLFS_FORCEVSYNCна ненулевое значение. -
QT_QPA_EGLFS_FORCE888- При установке значения игнорируются размер каналов красного, зеленого и синего цвета при создании нового контекста, окна или offscreen-поверхности. Вместо этого плагин запрашивает конфигурацию с 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 QuickQSG_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 с -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 dumb из-за устаревания fbdev в ядре Linux. Это необходимо запросить, установив переменную среды QT_QPA_FB_DRM в ненулевое значение. При установке, если система поддерживает буферы dumb, к устаревшим устройствам фреймбуфера, таким как /dev/fb0, никогда не обращаются. Вместо этого рендеринг настраивается через API DRM, аналогично бэкенду eglfs_kms eglfs. Вывод будет двойным буферизованным и перелистываться, обеспечивая правильную синхронизацию с вертикальной разверткой и для рендеринга с программным обеспечением.
Примечание: когда используются буферы dumb, ни один из описанных ниже параметров не применим, поскольку такие свойства, как физические и логические размеры экрана, запрашиваются автоматически.
Плагин 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) не установлены, и обнаружение устройств 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 и т. д.; эти сообщения можно безопасно игнорировать.
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, ширинаxвысота или строка режима.
Все экраны, сообщённые слоем 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 каждое из этих окон получит свою собственную отдельную нить отрисовки. Это хорошо, потому что потоки могут регулироваться независимо на основе 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 с бэкендом 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_NO_LIBINPUT.
При установке этих переменных будут использоваться только указанный разъем и слой, все другие выводы будут игнорироваться. Бэкенд позаботится о выборе слоя 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 МБ памяти графического процессора. Для систем, у которых нет фиксированного объема памяти, зарезервированной для графического процессора, эта проблема не возникает.
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 Wiki.
Связанные темы
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.9/embedded-linux.html