| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the documentation of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:FDL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Free Documentation License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Free |
| ** Documentation License version 1.3 as published by the Free Software |
| ** Foundation and appearing in the file included in the packaging of |
| ** this file. Please review the following information to ensure |
| ** the GNU Free Documentation License version 1.3 requirements |
| ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| /*! |
| \page embedded-linux.html |
| \title Qt for Embedded Linux |
| \brief Provides information about Embedded Linux support in Qt. |
| \ingroup supportedplatform |
| |
| On Embedded Linux systems, there are multiple platform plugins that you can |
| use: EGLFS, LinuxFB, DirectFB, or Wayland. However, the availability of these |
| plugins depend on how Qt is configured. |
| |
| EGLFS is the default plugin on many boards. If it's not suitable, use the |
| \c QT_QPA_PLATFORM environment variable to request another plugin. |
| Alternatively, for quick tests, use the \c -platform command-line argument |
| with the same syntax. |
| |
| \note As of Qt 5.0, Qt no longer has its own window system (QWS) |
| implementation. For single-process use cases, the \l{Qt Platform Abstraction} |
| is a superior solution; multi-process use cases are supported through |
| \l{Qt Wayland Compositor}{Wayland}. |
| |
| \section1 Platform Plugins for Embedded Linux Devices |
| |
| \target embedded eglfs |
| \section2 EGLFS |
| |
| \l {http://www.khronos.org/egl}{EGL} is an interface between OpenGL and the |
| native windowing system. Qt can use EGL for context and surface management, |
| however the API contains no platform-specifics. Creating a \e {native window}, |
| which won't necessarily be an actual window on the screen, must still be |
| done by platform-specific means. This is why we need the board or GPU-specific |
| adaptation code. Typically, these adaptations are provided as: |
| |
| \list |
| \li \e{EGLFS hooks} -- a single source file compiled into the platform |
| plugin |
| \li \e{EGL device integration} -- dynamically loaded plugins |
| \endlist |
| |
| EGLFS is a platform plugin for running Qt5 applications on top of EGL and |
| OpenGL ES 2.0, without an actual windowing system like X11 or Wayland. In |
| addition to Qt Quick 2 and native OpenGL applications, EGLFS supports |
| software-rendered windows, like QWidget, too. For QWidget, the widgets' |
| contents are rendered using the CPU into images, which are then |
| uploaded into textures and composited by the plugin. |
| |
| EGLFS is the recommended plugin for modern Embedded Linux devices that |
| include a GPU. |
| |
| EGLFS forces the first top-level window - either a QWidget or a QQuickView |
| - to become fullscreen. This window is also chosen to be the \e root widget |
| window into which all other top-level widgets are composited. For example, |
| dialogs, popup menus, or combo boxes. This behavior is necessary because |
| with EGLFS there is always exactly one native window and one EGL window |
| surface; these belong to the widget or window that is created first. This |
| approach works well when there is a main window that exists for the |
| application's lifetime and all other widgets are either non top-levels or are |
| created afterwards, once the main window is shown. |
| |
| There are further restrictions for OpenGL-based windows. EGLFS supports a |
| single single fullscreen GL window (as of Qt 5.3), like OpenGL-based QWindow, |
| a QQuickView, or a QOpenGLWidget. Opening additional OpenGL windows or mixing |
| such windows with QWidget-based content isn't supported; Qt terminates the |
| application with an error message. |
| |
| If necessary, \c eglfs can be configured using the following environment |
| variables: |
| |
| \table 100% |
| \header |
| \li Environment Variable |
| \li Description |
| \row |
| \li \c {QT_QPA_EGLFS_INTEGRATION} |
| \li In addition to the compiled-in \e hooks, it is also possible to use |
| dynamically loaded plugins to provide device or vendor-specific |
| adaptation. This environment variable enforces a specific plugin. |
| For example, setting it to \e{eglfs_kms} uses the KMS/DRM backend. |
| This is only an option when no static or compiled-in hooks were |
| specified in the device makespecs. In practice, the traditional |
| compiled-in hooks are rarely used, almost all backends are now |
| migrated to plugins. The device makespecs still contain a relevant |
| \c EGLFS_DEVICE_INTEGRATION entry: the name of the preferred backend |
| for that particular device. This is optional, but very useful to |
| avoid the need to set this environment variable if there are more |
| than one plugin present in the target system. In a desktop |
| environment the KMS or X11 backends are prioritized, depending on |
| the presence of the \c DISPLAY environment variable. |
| \note On some boards a special value of \c none is used instead |
| of an actual plugin. This indicates that no special integration is |
| necessary to use EGL with the framebuffer; no plugins must be loaded. |
| \row |
| \li \c {QT_QPA_EGLFS_PHYSICAL_WIDTH} and \c {QT_QPA_EGLFS_PHYSICAL_HEIGHT} |
| \li Specifies the physical screen's width and height in millimeters. On |
| platforms where the value can't be queried from the framebuffer |
| device \e{/dev/fb0} or via other means, a default DPI of 100 is used. |
| Use this variable to override any such defaults. Setting this variable |
| is important because QWidget- or Qt Quick Controls-based applications |
| rely on these values. Running these applications with the hard-coded |
| settings may result in user interface elements with sizes that are |
| unsuitable for the display in use. |
| \row |
| \li \c {QT_QPA_EGLFS_ROTATION} |
| \li Specifies the rotation applied to software-rendered content in |
| QWidget-based applications. Supported values are 180, 90, and -90. |
| This variable does not apply to OpenGL-based windows, including Qt |
| Quick. Qt Quick applications can apply transformations in their QML |
| scene instead. The standard \c eglfs mouse cursor always takes the |
| value into account, with an appropriately positioned and rotated |
| pointer image, regardless of the application type. However, special |
| cursor implementations, such as the KMS/DRM backend's hardware |
| cursor, may not support rotation. |
| \row |
| \li \c {QT_QPA_EGLFS_FORCEVSYNC} |
| \li When set, \c eglfs requests \c FBIO_WAITFORVSYNC on the framebuffer |
| device after each call to eglSwapBuffers(). This variable is only |
| relevant for backends relying on the legacy Linux \c fbdev subsystem. |
| Normally, with a default swap interval of 1, Qt assumes that calling |
| eglSwapBuffers() takes care of vsync; if it doesn't (for example, |
| due to driver bugs), try setting \c QT_QPA_EGLFS_FORCEVSYNC to a |
| non-zero value. |
| \row |
| \li \c {QT_QPA_EGLFS_FORCE888} |
| \li When set, the red, green, and blue color channel sizes are ignored |
| when \c eglfs creates a new context, window or offscreen surface. |
| Instead, the plugin requests a configuration with 8 bits per channel. |
| This can be helpful on devices where configurations with less than 32 |
| or 24 bits per pixel (for example, 5-6-5 or 4-4-4) are chosen by |
| default despite knowing they are not ideal, for example, due to |
| banding effects. Instead of changing application code, this variable |
| provides a shortcut to force 24 or 32 bpp configurations. |
| \endtable |
| |
| Additionally, the following less commonly used variables are available: |
| |
| \table 100% |
| \header |
| \li Environment Variable |
| \li Description |
| \row |
| \li \c {QT_QPA_EGLFS_FB} |
| \li Overrides the framebuffer device. The default is \c /dev/fb0. On most |
| embedded platforms this variable isn't very relevant because the |
| framebuffer is used only to query settings like the display |
| dimensions. However, on certain devices, this variable provides the |
| ability to specify which display to use in multiple display setups, |
| similar to the \c fb parameter in LinuxFB. |
| \row |
| \li \c {QT_QPA_EGLFS_WIDTH} and \c {QT_QPA_EGLFS_HEIGHT} |
| \li Contains the screen's width and height in pixels. While \c eglfs |
| tries to determine the dimensions from the framebuffer device |
| \e{/dev/fb0}, this doesn't always work. It may be necessary to |
| manually specify the sizes. |
| \row |
| \li \c {QT_QPA_EGLFS_DEPTH} |
| \li Overrides the color depth for the screen. On platforms where the |
| framebuffer device \e{/dev/fb0} is not available or the query is not |
| successful, a default of \c 32 is used. Use this variable to override |
| any such defaults. |
| \note This variable only affects the color depth value reported by |
| QScreen. It has no connection to EGL configurations and the color |
| depth used for OpenGL rendering. |
| \row |
| \li \c {QT_QPA_EGLFS_SWAPINTERVAL} |
| \li By default, a swap interval of \c 1 is requested. This variable |
| enables synchronizing to the display's vertical refresh. Use this |
| variable to override the swap interval's value. For instance, passing |
| 0 disables blocking on swap, resulting in running as fast as possible |
| without any synchronization. |
| \row |
| \li \c {QT_QPA_EGLFS_DEBUG} |
| \li When set, some debugging information is printed on the debug output. |
| For example, the input QSurfaceFormat and the properties of the |
| chosen EGL configuration are printed while creating a new context. |
| When used together with Qt Quick's \c {QSG_INFO} variable, you can |
| get useful information for troubleshooting issues related to the EGL |
| configuration. |
| \endtable |
| |
| In addition to \c {QT_QPA_EGLFS_DEBUG}, \c eglfs also supports Qt's modern |
| categorized logging system. The following logging categories are available: |
| |
| \list |
| |
| \li \c qt.qpa.egldeviceintegration – Enables logging for dynamically loaded |
| backends. Use this category to check what backend is in use. |
| \li \c qt.qpa.input – Enables debug output both from the \c evdev and |
| \c libinput input handlers. Use this category to check if a given input |
| device was recognized and opened. |
| \li \c qt.qpa.eglfs.kms – Enables verbose logging in the KMS/DRM backend. |
| \endlist |
| |
| After running \c configure, make sure to inspect its output. This is the |
| easiest, quickest way to identify whether you have the necessary EGLFS |
| backend, libudev, or libinput enabled. In short, if there's an undesired |
| "no" in your \c configure output, run: |
| |
| \code |
| ./configure -v |
| \endcode |
| |
| to turn on the verbose output, so that you can see the compiler and linker |
| invocations for each configure test. |
| |
| \note If you encounter errors about missing headers, libraries, or seemingly |
| cryptic linker failures, often, they are a sign of an incomplete or broken |
| sysroot and isn't related to Qt. |
| |
| As an example, when targeting the Raspberry Pi with the Broadcom proprietary |
| graphics drivers, the output should contain something like the following: |
| |
| \badcode |
| 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 |
| \endcode |
| |
| If this is not the case, it's not advisable to proceed further with the build |
| since accelerated graphics won't be functional without the Raspberry |
| Pi-specific backend, even if the rest of Qt compiles successfully. |
| |
| \section2 LinuxFB |
| |
| This plugin writes directly to the framebuffer via Linux's fbdev subsystem. |
| Only software-rendered content is supported. Note that on some setups |
| the display performance is expected to be limited. |
| |
| However, since fbdev is being deprecated in the Linux kernel, the DRM dumb |
| buffer support is also available, as of Qt 5.9. To use it, set the |
| \c QT_QPA_FB_DRM environment variable to a non-zero value. When set, provided |
| that dumb buffers are supported by your system, legacy framebuffer devices |
| like \c{/dev/fb0} won't be accessed. Instead, the rendering is set up via the |
| DRM APIs, similar to the \c{eglfs_kms} backend in EGLFS. The output is |
| double-buffered and page flipped, providing proper vsync for |
| software-rendered content as well. |
| |
| \note When dumb buffers are in use, none of the options described below are |
| applicable since properties like physical and logical screen sizes are all |
| queried automatically. |
| |
| The \c linuxfb plugin allows you to specify additional settings via the |
| \c QT_QPA_PLATFORM environment variable or \c -platform command-line option. |
| For example, \c {QT_QPA_PLATFORM=linuxfb:fb=/dev/fb1} specifies that the |
| framebuffer device \c /dev/fb1 must be used instead of the default \c fb0. |
| To specify multiple settings, separate the mwith a colon (:). |
| |
| \table |
| \header |
| \li Settings |
| \li Description |
| \row |
| \li \c {fb=/dev/fbN} |
| \li Specifies the framebuffer devices. On multiple display setups, |
| this setting allows you to run the application on different displays. |
| Currently, there's no way to use multiple framebuffers from one Qt |
| application. |
| \row |
| \li \c{size=}\e{<width>}\c{x}\e{<height>} |
| \li Specifies the screen size in pixels. The plugin tries to query the |
| display dimensions, both physical and logical, from the framebuffer |
| device. However, this query may not always lead to proper results; |
| it may be necessary to specify the values explicitly. |
| \row |
| \li \c{mmsize=}\e{<width>}\c{x}\e{<height>} |
| \li Specifies the physical width and height in millimeters. |
| \row |
| \li \c{offset=}\e{<width>}\c{x}\e{<height>} |
| \li Specifies the top-left corner of the screen offset in pixels. The |
| default position is at \c{(0, 0)}. |
| \row |
| \li \c {nographicsmodeswitch} |
| \li Specifies not to switch the virtual terminal to graphics mode |
| (\c KD_GRAPHICS). Typically, \e enabling graphics mode disables the |
| blinking cursor and screen blanking. However, when this parameter is |
| set, those two features are also skipped. |
| \row |
| \li \c {tty=/dev/ttyN} |
| \li Overrides the virtual console. Only used when \c{nographicsmodeswitch} |
| isn't set. |
| \endtable |
| |
| As of Qt 5.9, the behavior of EGLFS and LinuxFB have been synchronized, with |
| regards to the window sizing policy: the first top-level window is forced to |
| cover the entire screen, with both platform plugins. If this is not desired, |
| set the \c{QT_QPA_FB_FORCE_FULLSCREEN} environment variable to \c 0 to |
| restore the behavior from earlier Qt versions. |
| |
| \section1 Display Output |
| |
| When you have multiple displays connected, the level of support to target one |
| or more of these displays from one single Qt application, varies between the |
| platform plugins and often depends on the device and its graphics stack. |
| |
| \section2 EGLFS with the eglfs_kms Backend |
| |
| When the KMS/DRM backend is in use, EGLFS reports all available screens in |
| QGuiApplication::screens(). Applications can target different screens with |
| different windows via QWindow::setScreen(). |
| |
| \note The restriction of one single fullscreen window per screen still |
| applies. Changing screens after making the QWindow visible isn't supported |
| either. Therefore, it's essential that embedded applications make all the |
| necessary QWindow::setScreen() calls before calling QWindow::show(). |
| |
| When you start developing on a given embedded device, often it's necessary to |
| verify the behavior of the device and drivers, and that the connected displays |
| are working as they should. One easy way is to use the \b{hellowindow} example. |
| Launching it with the \c{-platform eglfs --multiscreen --timeout} arguments |
| shows a rotating Qt logo on each connected screen for a few seconds. |
| |
| The KMS/DRM backend also supports custom configurations via a JSON file. To |
| enable this, set the \c QT_QPA_EGLFS_KMS_CONFIG environment variable to the |
| name of the file. You can also embed this file into the application via the Qt |
| resource system. |
| |
| Most of these configuration options apply to all KMS/DRM-based backends, |
| regardless of the buffer management technology (GBM or EGLStreams). |
| |
| Here's an example configuration: |
| |
| \badcode |
| { |
| "device": "/dev/dri/card1", |
| "hwcursor": false, |
| "pbuffers": true, |
| "outputs": [ |
| { |
| "name": "VGA1", |
| "mode": "off" |
| }, |
| { |
| "name": "HDMI1", |
| "mode": "1024x768" |
| } |
| ] |
| } |
| \endcode |
| |
| Here we configure the specified device so that: |
| |
| \list |
| \li It won't use the hardware cursor (falls back to rendering the mouse |
| cursor via OpenGL; by default hardware cursors are enabled as they're |
| more efficient). |
| \li It backs QOffscreenSurface with standard EGL pbuffer surfaces (by |
| default this is disabled and a gbm surface is used instead). |
| \li Output on the VGA connector is disabled, while HDMI is active with a |
| resolution of 1024x768. |
| \endlist |
| |
| Additionally, such a configuration also disables looking for a device via |
| \c libudev; instead the specified device is used. |
| |
| When \c mode is not defined, the system's preferred mode is chosen. The |
| accepted values for \c mode are: \c off, \c current, \c preferred, \c skip, |
| width\c{x}height, width\c{x}height\c{@}vrefresh, or a modeline string. |
| |
| Specifying \c current chooses a mode with a resolution that matches the |
| current one. Because modesetting is done only when the desired mode is |
| actually different from the active one (unless forced via the |
| \c QT_QPA_EGLFS_ALWAYS_SET_MODE environment variable), this value is useful to |
| preserve the current mode and any content in the planes not touched by Qt. |
| |
| \c skip causes the connector for the output to be ignored, as if it were |
| disconnected. \c off is similar, but it changes the mode and turns off the |
| display. |
| |
| By default, all screens reported by the DRM layer are treated as one big virtual |
| desktop. The mouse cursor implementation takes this into account and moves |
| across the screens as expected. Although not recommended, you can disable the |
| virtual desktop by setting \c separateScreens to \c false in the configuration. |
| |
| By default, the virtual desktop is formed left to right, based on the order of |
| connectors as reported by the system. To change this, set \c virtualIndex to a |
| value starting from 0. |
| |
| For example, the following configuration uses the preferred resolution but ensures |
| that the left side in the virtual desktop is the screen connected to the HDMI port; |
| while the right side is the screen connected to the DisplayPort: |
| |
| \badcode |
| { |
| "device": "drm-nvdc", |
| "outputs": [ |
| { |
| "name": "HDMI1", |
| "virtualIndex": 0 |
| }, |
| { |
| "name": "DP1", |
| "virtualIndex": 1 |
| } |
| ] |
| } |
| \endcode |
| |
| The order of elements in the array is not relevant. Outputs with unspecified |
| virtual indices are placed after the others, with the original order in the |
| DRM connector list preserved. |
| |
| To create a vertical desktop space (that is, to stack top to bottom instead of |
| left to right), add a \c virtualDesktopLayout property after \c device |
| with the value of \c vertical. |
| |
| \warning It's recommended that all screens in the virtual desktop use the same |
| resolution, otherwise elements like the mouse cursor may behave in unexpected |
| ways when entering areas that only exist on one given screen. |
| |
| When \c virtualIndex is not sufficient, the \c virtualPos property can be used |
| to explicitly specify the top-left position of the screen in question. Taking |
| the previous example and assuming a resolution of 1080p for HDMI1, the |
| following code snippet places a second HDMI-based screen below the first one: |
| |
| \badcode |
| { |
| ... |
| "outputs": [ |
| ... |
| { |
| "name": "HDMI2", |
| "virtualPos": "0, 1080" |
| } |
| ] |
| } |
| \endcode |
| |
| \note Avoid such configurations when mouse support is desired. The mouse |
| cursor's behavior may be unexpected with non-linear layouts. Touch should |
| present no issues however. |
| |
| In some cases the automatic querying of the physical screen size via DRM may |
| fail. Normally the \c QT_QPA_EGLFS_PHYSICAL_WIDTH and |
| \c QT_QPA_EGLFS_PHYSICAL_HEIGHT environment variable would be used to provide the |
| missing values, however this is not suitable anymore when multiple screens are |
| present. Instead, use the \c physicalWidth and \c physicalHeight properties |
| in the \c outputs list to specify the sizes in millimeters. |
| |
| \note Different physical sizes and thus differing logical DPIs are discouraged |
| because it may lead to unexpected issues due to some graphics stack components |
| not knowing about multiple screens and relying solely on the first screen's |
| values. |
| |
| Each active output from the \c outputs array corresponds to one QScreen |
| instance reported from QGuiApplication::screens(). By default, the primary screen |
| that QGuiApplication::primaryScreen() reports is the screen that is registered |
| first. If you're not using \c virtualIndex, this means the decision is based on |
| the DRM connector order. To override this, set the \c primary property to \c true |
| on the desired entry in the \c outputs list. |
| |
| For example, to ensure the screen corresponding to the VGA output is the primary even |
| when the system happens to report the HDMI one first, do the following: |
| |
| \badcode |
| { |
| "device": "/dev/dri/card0", |
| "outputs": [ |
| { "name": "HDMI1" }, |
| { "name": "VGA1", "mode": "1280x720", "primary": true }, |
| { "name": "LVDS1", "mode": "off" } |
| ] |
| } |
| \endcode |
| |
| For troubleshooting it might be useful to enable debug logs from the KMS/DRM |
| backend. To do this, enable the \c qt.qpa.eglfs.kms categorized logging rule. |
| |
| \note In an embedded environment, virtual desktops are more limited compared to |
| a full windowing system. Windows overlapping multiple screens, non-fullscreen |
| windows, and moving windows between screens, should be avoided and may not |
| function as expected. |
| |
| The most common and best supported use case for a multi-screen setup is to |
| open a dedicated QQuickWindow or QQuickView for each screen. With the default |
| \c threaded render loop of the Qt Quick scenegraph, each of these windows will |
| get its own dedicated render thread. This is good because the threads can be |
| throttled independently based on vsync, and will not interfere with each |
| other. With the \c basic loop this can get problematic, causing animations to |
| degrade. |
| |
| For example, discovering all connected screens and creating a QQuickView for |
| each of them can be done like this: |
| |
| \badcode |
| 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; |
| } |
| \endcode |
| |
| \section2 Advanced eglfs_kms Features |
| |
| As of Qt 5.11, screen cloning (mirroring) is supported. This is enabled via |
| the \c clones property: |
| |
| \badcode |
| { |
| "device": "/dev/dri/card0", |
| "outputs": [ |
| { "name": "HDMI1", "mode": "1920x1080" }, |
| { "name": "DP1", "mode": "1920x1080", "clones": "HDMI1" } |
| ] |
| } |
| \endcode |
| |
| In this case, the content on the display connected via DisplayPort will be the |
| same as on the HDMI one. This is ensured by scanning out the same buffer on |
| both. |
| |
| However, this feature can only work if the resolutions are the same, there are no |
| incompatibilities when it comes to accepted buffer formats, and the application |
| doesn't have any output on the QScreen associated with a clone destination. In |
| practice, the latter means that no QWindow associated with the QScreen in question |
| - DP1 in the example - must ever perform a QOpenGLContext::swapBuffers() operation. |
| It's up to the configuration and the application to ensure these. |
| |
| As of Qt 5.11, headless mode via DRM render nodes is supported. This allows |
| performing GPU compute (OpenGL compute shaders, OpenCL) or offscreen OpenGL |
| rendering without needing DRM master privileges. In this mode, applications can |
| function even when there is already another process outputting to the screen. |
| |
| Just switching \c device from \c{/dev/dri/card0} to \c{/dev/dri/renderD128} is |
| futile on its own since there are a number of operations that cannot be |
| performed in headless mode. Therefore, this must be combined with a |
| \c headless property, for example: |
| |
| \badcode |
| { |
| "device": "/dev/dri/renderD128", |
| "headless": "1024x768" |
| } |
| \endcode |
| |
| Keep in mind that windows are still sized to match the - now virtual - |
| screen size, hence the need for specifying a size in the \c headless |
| property. There is also a lack of vsync-based throttling. |
| |
| Once enabled, applications have two typical choices to perform offscreen |
| rendering in headless mode: |
| |
| Use an ordinary window, such as a QOpenGLWindow subclass, targeting the |
| window's default framebuffer, meaning a \c{gbm_surface} in practice: |
| |
| \badcode |
| MyOpenGLWindow w; |
| w.show(); // will not actually show up on screen |
| w.grabFramebuffer().save("output.png"); |
| \endcode |
| |
| Or the typical offscreen approach with an extra FBO: |
| |
| \badcode |
| 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(); |
| \endcode |
| |
| KMS/DRM can be used with two different DRM APIs which are \e legacy and \e atomic. |
| The main benefit of DRM atomic API is to allow several DRM plane updates |
| within the same renderloop, whereas legacy API would require one plane update |
| per vsync. |
| |
| Atomic API is useful when you application needs to blend content into overlays |
| keeping all the updates within the same vsync. Still not all devices |
| support this API and it could be unavailable on some older devices. |
| KMS backend will by default use the legacy API, but you can enable the DRM |
| atomic API with \c QT_QPA_EGLFS_KMS_ATOMIC environment variable set to 1. |
| |
| Using a smaller framebuffer than screen resolution can also be useful. |
| This is possible with DRM atomic using the \c size parameter in the JSON file. |
| The example below uses a 1280x720 framebuffer on a 3840x2160 videomode : |
| |
| \badcode |
| { |
| "device": "/dev/dri/card0", |
| "outputs": [ |
| { "name": "HDMI1", "mode": "3840x2160", "size": "1280x720", "format": "argb8888" } |
| ] |
| } |
| \endcode |
| |
| \section2 eglfs with eglfs_kms_egldevice backend |
| |
| This backend, typically used on Tegra devices, is similar to the KMS/DRM |
| backend mentioned above, except that it relies on the EGLDevice and EGLStream |
| extensions instead of GBM. |
| |
| For technical details about this approach, check out |
| \l {https://wiki.qt.io/Qt_for_Embedded_Linux/XDC2014RitgerEGLNonMesa}{this presentation}. |
| |
| As of Qt 5.7 this backend shares many of its internal implementation with the |
| GBM-based backend. This means that multiple screens and the advanced |
| configuration via \c QT_QPA_EGLFS_KMS_CONFIG are supported. Some settings, |
| such as \c hwcursor and \c pbuffers are not applicable however. |
| |
| By default the backend will automatically choose the correct EGL layer for the |
| default plane of each output. When necessary, this can be overridden by |
| setting the \c QT_QPA_EGLFS_LAYER_INDEX environment variable to the index of |
| the desired layer. This approach does not currently support multiple outputs, |
| so its usage should be limited to systems with a single screen. To see which |
| layers are available, and to debug potential startup issues, enable the |
| logging category \c qt.qpa.eglfs.kms. |
| |
| In some cases it may be necessary to perform a video mode set on application |
| startup even when the screen reports that the desired resolution is already |
| set. This is normally optimized away, but if the screen stays powered down, |
| try setting the environment variable \c QT_QPA_EGLFS_ALWAYS_SET_MODE to a |
| non-zero value and relaunch the application. |
| |
| To configure the behavior of the EGLStream object used by the backend, use the |
| \c QT_QPA_EGLFS_STREAM_FIFO_LENGTH environment variable. This assumes that |
| \c KHR_stream_fifo is supported by the target system. By default the stream |
| operates in mailbox mode. To switch to FIFO mode, set a value of 1 or |
| greater. The value specifies the maximum number of frames the stream can hold. |
| |
| On some systems it may become necessary to target a specific overlay plane |
| through a pre-defined connector. Just forcing a layer index via |
| \c QT_QPA_EGLFS_LAYER_INDEX does not perform plane configuration and is therefore |
| not suitable in itself. Instead, in such special scenarios use the |
| \c QT_QPA_EGLFS_KMS_CONNECTOR_INDEX and \c QT_QPA_EGLFS_KMS_PLANE_INDEX |
| environment variables. When these are set, only the specified connector and |
| plane will be in use, all other outputs will get ignored. The backend will |
| take care of picking the EGL layer that corresponds to the desired plane, and |
| the configuring of the plane. |
| |
| \section2 Touch input in systems with multiple screens on KMS/DRM |
| |
| Touchscreens require additional considerations in multi-display systems |
| because touch events have to be routed to the correct virtual screen, and this |
| requires a correct mapping between touchscreens and display outputs. |
| |
| The mapping is done via the JSON configuration file specified in |
| \c QT_QPA_EGLFS_KMS_CONFIG and described in the previous sections. When a |
| \c touchDevice property is present in an element of the \c outputs array, the |
| value is treated as a device node and the touch device is associated with the |
| display output in question. |
| |
| For example, assuming our touchscreen has a device node of /dev/input/event5 |
| and is a touchscreen integrated into the monitor connected via HDMI as the |
| secondary screen, the following configuration ensures correct touch (and |
| synthesized mouse) event translation: |
| |
| \badcode |
| { |
| "device": "drm-nvdc", |
| "outputs": [ |
| { |
| "name": "HDMI1", |
| "touchDevice": "/dev/input/event5", |
| "virtualIndex": 1 |
| }, |
| { |
| "name": "DP1", |
| "virtualIndex": 0 |
| } |
| ] |
| } |
| \endcode |
| |
| \note When in doubt, enable logging from both the graphics and input |
| subsystems by setting the environment variable |
| \c{QT_LOGGING_RULES=qt.qpa.*=true} before launching the application. This will |
| help identifying the correct input device nodes and may uncover output |
| configuration issues that can be difficult to debug otherwise. |
| |
| \note As of Qt 5.8, the above is only supported for the evdevtouch input |
| backend. Other variants, such as the libinput-based one, will continue to |
| route events to the primary screen. To force the usage of evdevtouch on |
| systems where multiple input backends are available, set the environment |
| variable \c QT_QPA_EGLFS_NO_LIBINPUT to \c 1. |
| |
| \section2 eglfs with other backends |
| |
| Other backends, that are typically based on targeting the framebuffer or a |
| composition API directly via the vendor's EGL implementation, usually provide |
| limited or no support for multiple displays. On i.MX6-based boards with |
| Vivante GPUs the \c{QT_QPA_EGLFS_FB} environment variable can be used to |
| specify the framebuffer to target, similarly to linuxfb. On the Raspberry Pi |
| the \c{QT_QPA_EGLFS_DISPMANX_ID} environment variable can be used to specify |
| the screen to output to. The value corresponds to one of the \c{DISPMANX_ID_} |
| constants, refer to the Dispmanx documentation. Note that these approaches, |
| unlike KMS/DRM, will not typically allow to output to multiple screens from |
| the same application. Alternatively, driver-specific environment variables or |
| kernel parameters may also be available as well to control the used |
| framebuffer. Refer to the embedded board's documentation. |
| |
| \section2 Video Memory |
| |
| Systems with a fixed amount of dedicated video memory may need extra care |
| before running Qt application based on Qt Quick or classes like |
| QOpenGLWidget. The default setting may be insufficient for such applications, |
| especially when they are displayed on a high resolution (for example, full HD) |
| screen. In this case, they may start failing in unexpected ways. It is |
| recommended to ensure that there is at least 128 MB of GPU memory available. |
| For systems that do not have a fixed amount of memory reserved for |
| the GPU this is not an issue. |
| |
| \section2 linuxfb |
| |
| Use the \c fb plugin parameter to specify the framebuffer device to use. |
| |
| \section1 Unix Signal Handlers |
| |
| The console-oriented platform plugins like eglfs and linuxfb install signal |
| handlers by default to capture interrupt (\c SIGINT), suspend and continue |
| (\c SIGTSTP, \c SIGCONT) and termination (\c SIGTERM). This way the keyboard, |
| terminal cursor, and possibly other graphics state can be restored when the |
| application terminates or gets suspended due to \c kill, or \c{Ctrl+C} or |
| \c{Ctrl+Z}. (although terminating or suspending via the keyboard is only |
| possible when \c{QT_QPA_ENABLE_TERMINAL_KEYBOARD} is set, as outlined above in |
| the Input section). However, in some cases capturing \c SIGINT can be |
| undesirable as it may conflict with remote debugging for instance. Therefore, |
| the environment variable \c{QT_QPA_NO_SIGNAL_HANDLER} is provided to opt out |
| from all built-in signal handling. |
| |
| \section1 Fonts |
| |
| Qt normally uses \c fontconfig to provide access to system fonts. If |
| \c fontconfig is not available, Qt will fall back to using |
| \c QBasicFontDatabase. In this case, Qt applications will look for fonts in Qt's |
| \c lib/fonts directory. Qt will automatically detect pre-rendered fonts and |
| TrueType fonts. This directory can be overridden by setting the \c |
| QT_QPA_FONTDIR environment variable. |
| |
| For more information on the supported formats, see \l{Qt for Embedded Linux Fonts}. |
| |
| \note Qt no longer ships any fonts in the \c lib/fonts directory. This |
| means that it is up to the platform (the system image) to provide the |
| necessary fonts. |
| |
| \section1 Platform Plugins for Windowing Systems on Embedded Linux Devices |
| |
| \section2 XCB |
| |
| This is the X11 plugin used on regular desktop Linux platforms. In some |
| embedded environments, that provide X and the necessary development files for |
| \l {http://xcb.freedesktop.org}{xcb}, this plugin functions just like it |
| does on a regular PC desktop. |
| |
| \note On some devices there is no EGL and OpenGL support available under X |
| because the EGL implementation is not compatible with Xlib. In this case the |
| XCB plugin is built without EGL support, meaning that Qt Quick 2 or other |
| OpenGL-based applications does not work with this platform plugin. It can |
| still be used however to run software-rendered applications (based on QWidget |
| for example). |
| |
| As a general rule, the usage of XCB on embedded devices is not |
| advisable. Plugins like eglfs are likely to provide better performance, and |
| hardware acceleration. |
| |
| \section2 Wayland |
| |
| \l{http://wayland.freedesktop.org/}{Wayland} is a light-weight windowing |
| system; or more precisely, it is a protocol for clients to talk to a display |
| server. |
| |
| Qt Wayland provides a \c wayland platform plugin that allows Qt applications |
| to connect to a Wayland compositor. |
| |
| For more details, see \l{Wayland and Qt}. |
| |
| \section1 Related Topics |
| |
| \list |
| \li \l{Qt for Device Creation} |
| \li \l{Configure an Embedded Linux Device} |
| \li \l{Inputs on an Embedded Linux Device} |
| \li \l Emulator |
| \li \l{Qt Virtual Keyboard} |
| \li \l{Qt Quick WebGL} |
| \endlist |
| |
| */ |