Qt for Embedded Linux and DirectFB

Introduction

DirectFB is an open source LGPL licensed project founded by Denis Oliver Kropp and generally chip vendors start out with the official version and implement their own plugins to optimize the operations their hardware supports.

We recommend using Qt 4.6 or later with DirectFB. Support for DirectFB was introduced into Qt for Embedded Linux as a labs project for Qt 4.3 and folded into Qt as a screen driver for Qt 4.4, but not supported fully. In Qt 4.5, major changes were made to make it work with the optimized raster paint engine. These changes were further improved in Qt 4.6.

Using DirectFB with Qt

DirectFB is centered around Surfaces which is the equivalent of a QPaintDevice. In the Qt/DirectFB plugin, DirectFB maps onto either a QPixmap or a QWindowSurface which essentially means that drawing onto QPixmap or a QWidget can be accelerated and drawing onto any other paint device (e.g. QImage) cannot.

Configure

When configuring Qt there are two options, from which you can choose:

./configure -plugin-gfx-directfb
./configure -qt-gfx-directfb

With either mode, Qt will try the following to look for the DirectFB includes/libs.

Use pkg-config

Use directfb-config

Check in your qmake.conf

Often the values returned from pkg-config/directfb-config indicates the locations of the libs/headers on the target rootfs, rather than their location on your host. The safest option is usually to explicitly populate these variables in your qmake.conf like this:

Note: While DirectFB supports a multi-process setup through a kernel-extension called Fusion this setup is not well tested with Qt.

Supported graphics operations

IDirectFBSurface supports blitting, filling, drawing lines rects etc, but it does not support everything Qt allows you to do. E.g. painter paths, polygons, complex transformations, antialiasing, gradients. Some of these things are handled in newer versions of DirectFB and could be supported by Qt. They are seemingly optional at the driver level, so you need to have fall back code paths for older drivers and drivers on which this is not implemented.

The QDirectFBPaintEngine is a subclass of the QRasterPaintEngine, thus essentially supporting everything QRasterPaintEngine supports. This means that it supports all graphical operations that Qt supports, but certain operations will have to fall back to software rendering and that should be avoided due to performance issues. Instead, these operations should be rendered into a QPixmap once, and then reuse the pixmap.

Note: Fallbacks to software rendering should be avoided. If unsupported operations are used, the paint engine must fallback to the QRasterPaintEngine engine. A good debugging tip is to make Qt warn you when such fall backs occur, and to disable the fall back and only return. Debugging options are listed below.

DirectFB driver

DirectFB also provides an abstraction for keyboard and mouse drivers. This simplifies the process of getting the target hardware up and running. It also brings us to a feature fragmentation issue between different versions of DirectFB.

The Qt DirectFB driver currently supports DirectFB versions >= 0.9. Still, there are large differences in what each actual implementation handles correctly. It is relatively common not to properly support DirectFB windows, so Qt needs to handle this case with a different code path. In addition, certain drivers do not properly support DirectFB's cursor handling. This means Qt has to have a code path for rendering the cursor itself when this is the case. Some drivers do not let us create preallocated surfaces which means we have to have a conditional code path for that case.

Optimize performance using define options

Qt/DirectFB comes with a number of defines that can be either uncommented in directfb.pri or added to the QT_DEFINES_DIRECTFB variable in your qmake.conf.

Note: The defines have been moved from src/plugins/gfxdrivers/directfb/directfb.pro to src/gui/embedded/directfb.pri

As demonstrated above, you need to tell Qt which drawing operations you want to warn/disable. Since there are varying implementations of DirectFB from manufacturer to manufacture, different operations will be optimized. This require you to define the operations you want to warn about or disable. These are listed above in the DIRECTFB_DRAWINGOPERATIONS variable.

You can also customize this with environment variables.

E.g. If you want to disable fallbacks for drawPixmap and fillRect and also get a warning printed on stderr when a fallback would have happened.

Defining this means that Qt will cache an IDirectFBSurface per QImage you draw based on its cacheKey(). Use this define if your application draws many QImages that remain the same. Note that if you in this situation draw an image and then change it, by calling bits() or opening a QPainter on it, the cache will not benefit you. You can control the cache size with the imageCacheSize connect option.

QT_NO_DIRECTFB_WM

If your DirectFB implementation does not support windows, you have to define this to make Qt work properly. You can test this by checking if the df_window example runs well. This means that all drawing operations onto a QWidget involves an extra blitting step since Qt essentially first has to draw into an off-screen buffer and then blit this buffer to the back buffer of the primary surface. Finally, Qt must flip the back buffer to the front buffer, which usually involves another blit. Still, blits are usually very fast with DirectFB.

To work around this you can make your widget paint on screen, Qt::WA_PaintOnScreen but this comes with other limitations. This should be avoided if you want more than one full-screen window in your application. In addition, it will not work without proper DirectFB mouse support from the layer. Also, see QT_NO_DIRECTFB_LAYER for more.

QT_NO_DIRECTFB_LAYER

If your DirectFB display layer cannot be used for e.g. drawing mouse cursor, creating windows you have to define this. Defining this also requires defining QT_NO_DIRECTFB_WM and involves making Qt render the cursor rather than letting DirectFB do it.

QT_NO_DIRECTFB_PALETTE

Define this if your DirectFB driver does not support surfaces with color tables. The effect of defining this is that Qt will have to convert images with QImage::Format_Indexed8 format to another format before rendering them.

QT_NO_DIRECTFB_PREALLOCATED

Define this if your DirectFB driver does not support creating a surface with preallocated data. This will make a more frequent use of memcpy() when drawing images. If you define this, you might want to consider defining QT_DIRECTFB_IMAGECACHE for better image rendering performance.

Define this when debugging to get output on stderr about the frames per second.

QT_NO_DIRECTFB_OPAQUE_DETECTION

When blitting a surface Qt has to decide whether to set the DSBLIT_BLEND_ALPHACHANNEL flag. If you load an image from file or network data that has a format that includes an alpha channel, the image might still be completely opaque. Normally Qt runs through every pixel to check if there really is an alpha channel there. This involves some overhead but usually pays off in the end because blitting is cheaper than blending. If you define this Qt will assume that an image with a format that has alpha channel contains at least one pixel with an alpha value != 255.

QT_DIRECTFB_SUBSURFACE

Defining this enables a mode that tries to minimize overhead from locking/unlocking surfaces. Note that this currently is experimental.

QT_DIRECTFB_WINDOW_AS_CURSOR

Define this if your DirectFB implementation supports windows but can not render the cursor properly. This involves creating a small top level window and moving it around when the cursor moves. It does not always perform well.

QT_NO_DIRECTFB_IMAGEPROVIDER

By default Qt will use DirectFB to load QPixmaps from disk/memory. If your DirectFB implementation does not support this it might make sense to define this. If you see strange rendering issues with pixmaps that have an alpha channel defining this could solve the problem.

QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE

Define this to make sure Qt always keeps at least one IDirectFBImageProvider object alive. This is to avoid considerable overhead when the first IDirectFBImageProvider is created, the last IDirectFBImageProvider is removed.

Unsupported graphics operations

There are a number of unsupported operations causing fallbacks. DirectFB does not support the following functions.

When painting images

Note: You should use QPixmap instead of QImage. QImages are drawn by the QRasterPaintEngine. To get a warning for every fallback to the QRasterPaintEngine, use QT_DIRECTFB_WARN_ON_RASTERFALLBACKS. If QT_DIRECTFB_DISABLE_RASTERFALLBACKS is defined, DirectFB will only return instead of falling back to QRasterPaintEngine. Please note that these defines should only be used when optimizing the application.

Top level transparency

Note: DirectFB supports partially or fully transparent top level windows, either through QWidget::setWindowOpacity or through setting a non-opaque background brush. Note that for the latter it is not supported to change an opaque window to be transparent at runtime.