Donald Carr
OpenGL
Embedded
Build system
Posted by Donald Carr
 in OpenGL, Embedded, Build system
 on Friday, February 05, 2010 @ 10:49

Requirements

1) Tegra 2 platform
2) The latest Nvidia Tegra2 SDK (11.0074_devlite_eula_Beta-RC.zip at this time)

Board bring up

Nvidia have done a pretty good job in documenting bring up and I will not
paraphrase them. I personally used their dev environment exactly as
intended (answering every question posed during installation with an
affirmative), so my dev machine became a DHCP/NFS server serving out on a
secondary network interface. Be sure to select an X enabled SDK during installation as we
currently don’t work out of the box with their OpenKode drivers.

Their supplied documentation (in chm format) is thorough and documents
flashing the latest bootloader to the device (amongst other things) which I would
recommended on every update, to ensure targetfs/bootloader compatibility.

Initial rootfs adjustment/configuration

Once you have installed both packages included in
11.0074_devlite_eula_Beta-RC.zip you should have 2 dirs:

emPower-devlite-p1138
toolchains

Go into:

./emPower-devlite-p1138

cp -r include/* targetfs/usr/include
cp -r lib-target/* targetfs/usr/lib

your targetfs is now primed for GL compilation. You will need to boot your
target prior to proceeding though, as on first boot a host of packages
are installed into the targetfs including all the X11 headers required to
compile Qt/X11.

Additional headers (dbus, glib, freetype, gstreamer) might be
required for a full featured Qt build, but the packages installed on first
boot will suffice for a OpenGL ES 2 enabled Qt/X11 build with all of Qt’s
core functionality.

Go to town with apt-get according to your needs
(apt-get build-dep libqt4-gui unfortunately fails due to unmet
dependencies) and please be aware of the fact that the chm documentation
covers forwarding net traffic between your Tegra2 target and the external
world via your host machine.

Once this is done, we are ready to build qt.

Configuring build environment

I use Scratchbox 2 for reasons qualified in the appendix.

1) Change to your targetfs directory (cd $NV_ROOT/emPower-devlite-p1138/targetfs)

2) Run:

sb2-init -c /usr/bin/qemu-arm $SB2-TARGETNAME $NV_ROOT/toolchains/tegra2-4.3.2-nv/bin/arm-none-linux-gnueabi-gcc

within this directory, where:

$SB2-TARGETNAME is a suitable name for your target’s scratchbox environment
$NV_ROOT is where you unpacked the archive

You now have a sane scratchbox 2 env when you can compile Qt/X11. If you
were to enter the scratchbox env and build Qt now, it would get through
every module up until QtOpenGL was reached, at which point you would
witness spaghetti breakage referencing the inclusion of the qdebug/text
streaming classes.

This is because

targetfs/usr/include/EGL/eglplatform.h

includes several X11 headers:

Xlib.h
Xutil.h

as it explicitly references native X11 types. I initially tried to move
these headers out of this header file, but the path of least resistance
ended up being the undefining of conflicting defines at the end of the
eglplatform.h header file.

I introduced the following 4 lines:

#undef None
#undef Status
#undef Unsorted
#undef GrayScale

immediately prior to the final #endif in this file. I know this is dirty,
but it circumvents the point of breakage and resolves all remaining build failures.

Having done this, we are ready to build Qt/X11.

Building Qt

1) Enter scratchbox 2 with: sb2 -t $SB2-TARGETNAME
2) Enter your Qt directory
3) Configure Qt with (at a minimum):
./configure -xplatform linux-g++ -platform linux-host-g++ -opengl es2 -force-pkg-config ..
(The utilized mkspecs are discussed in the Appendix)
4) Check the output of configure to verify OpenGL ES2 (and any other
functionality you wish to build) has been correctly detected and enabled by
the configure tests.
5) run “make” (Qt should build through to completion)
6) “make install” Qt to its prefix path on the host (if necessary)
7) Use Qt to compile any appropriate Qt applications within the
scratchbox env
8 ) Deploy Qt to its prefix path (on the target) with any desired
applications

When you boot your Tegra2 platform, start X and launch your
OpenGL ES2 enabled Qt application (Either GLES2 content directly
in QGLWidget ala hellogl_es2, a QGLWidget fronted QGraphicsView
or via explicit use of the OpenGL ES2 graphics system), everything
should simply work to a greater or lesser extent and work at pace
at that.

We have not done any profiling of Qt on the Tegra2
hardware in order to quantify where we are today, nor any
dedicated integration in order to be maximize our use of the
underlying hardware but the baseline performance is very solid.

Appendix

mkspec information

linux-g++

the generic linux X11 mkspec, which behind the curtains of scratchbox
is mapped to the (environment creation time) specified cross compiler.

linux-host-g++

a modification of the generic linux X11 mkspec, which maps to the host machines compiler. This
mkspec is already present in the Qt maemo5 branch on our git repository. This
mkspec is basically a modification of linux-g++, with “host-” prefixed on
all the compiler variables. (included from ../common/g++.conf) The only
noteworthy thing about this mkspec is that instead of including
“../common/g++.conf” and modifying select variables accordingly, the
complete include is inlined. This is due to a known issue where overriding
QMAKE_CXX variables in not respected during the qmake boot strapping
process.

The linux-host-g++ mkspec looks roughly like this:

=============================================

#
# qmake configuration for linux-g++
#

MAKEFILE_GENERATOR = UNIX
TEMPLATE = app
CONFIG += qt warn_on release incremental link_prl
QT += core gui
QMAKE_INCREMENTAL_STYLE = sublib

#
# qmake configuration for common gcc
#

#inlined ../common/g++.conf follows

QMAKE_CC = host-gcc
QMAKE_CFLAGS += -pipe
QMAKE_CFLAGS_DEPS += -M
QMAKE_CFLAGS_WARN_ON += -Wall -W
QMAKE_CFLAGS_WARN_OFF += -w
QMAKE_CFLAGS_RELEASE += -O2
QMAKE_CFLAGS_DEBUG += -g
QMAKE_CFLAGS_SHLIB += -fPIC
QMAKE_CFLAGS_STATIC_LIB += -fPIC
QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses
QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden
QMAKE_CFLAGS_PRECOMPILE += -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
QMAKE_CFLAGS_USE_PRECOMPILE += -include ${QMAKE_PCH_OUTPUT_BASE}

QMAKE_CXX = host-g++
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_DEPS += $$QMAKE_CFLAGS_DEPS
QMAKE_CXXFLAGS_WARN_ON += $$QMAKE_CFLAGS_WARN_ON
QMAKE_CXXFLAGS_WARN_OFF += $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_SHLIB += $$QMAKE_CFLAGS_SHLIB
QMAKE_CXXFLAGS_STATIC_LIB += $$QMAKE_CFLAGS_STATIC_LIB
QMAKE_CXXFLAGS_YACC += $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_HIDESYMS += $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden
QMAKE_CXXFLAGS_PRECOMPILE += -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE

QMAKE_LINK = host-g++
QMAKE_LINK_SHLIB = host-g++
QMAKE_LINK_C = host-gcc
QMAKE_LINK_C_SHLIB = host-gcc
QMAKE_LFLAGS +=
QMAKE_LFLAGS_RELEASE += -Wl,-O1
QMAKE_LFLAGS_DEBUG +=
QMAKE_LFLAGS_APP +=
QMAKE_LFLAGS_SHLIB += -shared
QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB
QMAKE_LFLAGS_SONAME += -Wl,-soname,
QMAKE_LFLAGS_THREAD +=
QMAKE_LFLAGS_NOUNDEF += -Wl,–no-undefined
QMAKE_RPATH = -Wl,-rpath,

QMAKE_PCH_OUTPUT_EXT = .gch

# -Bsymbolic-functions (ld) support
QMAKE_LFLAGS_BSYMBOLIC_FUNC = -Wl,-Bsymbolic-functions
QMAKE_LFLAGS_DYNAMIC_LIST = -Wl,–dynamic-list,

include(../common/linux.conf)

=============================================

Scratchbox

I personally use Scratchbox 2 rather than Scratchbox 1 since I use a 64 bit
distro, and Scratchbox 2 exists in the Ubuntu repositories.

http://packages.ubuntu.com/search?keywords=scratchbox&searchon=names&suite=karmic&section=all

You might get equally good mileage with Scratchbox 1, or entirely without
Scratchbox. I personally opt for the path of least resistance, and this blog is a cart
following that path.

Arguments in favour of Scratchbox

1) pkg-config in Ubuntu 9.10 does not support prefixes (sysroot) correctly,
so you have to directly modify the .pc files or build pkg-config yourself
2) The Nvidia targetfs/usr/lib entries often have fully qualified symlinks which link
into your host machines libs without a chroot safety net
3) There were some toolchain/targetfs anomalies which simply vanished when adopting this build approach

Known issues

1)The aforementioned qmake bootstrapping issue preventing QMAKE_CXX being over ridden in linux-host-g++
2) 16 bit X is the only environment tested and known to work. Qt GLES2 applications currently segfault
on launch under a 24 bit X session. I am busy investigating this issue. Please ensure that your xorg.conf file is using
16 bit as the default/selected color depth if you intend to run Qt apps.
3) libEGL.so prints a spurious error message:

“”Couldn’t load implementation for OpenGL_ES”

due to the absence of an libGLES(1).so which, it appears, can be safely ignored

Donald Carr
Qt
Graphics View
Painting
OpenGL
Performance
Embedded
Build system
Posted by Donald Carr
 in Qt, Graphics View, Painting, OpenGL, Performance, Embedded, Build system
 on Friday, November 20, 2009 @ 00:53

Introduction

Texas Instruments has a wiki which documents what is required to bring Qt
up on the Beagle board with full OpenGL ES (1/2) support:

http://www.tiexpressdsp.com/index.php/Building_Qt

and I would like to thank one of their engineers, Varun, for his quick turn
around times in addressing any questions I raised.

This blog entry is intended to serve a similar purpose, but is more verbose regarding
Qt considerations and the initial beagle board bring up. It attempts to serve
as a comprehensive independent source of information on getting Qt built
for the Beagle board with full OpenGL ES 2 support.

These instructions are intended for use with Qt 4.6 (and beyond), so grab
the release candidate or check Qt 4.6 out from the public git repository prior
to proceeding.

You can choose to use either Qt/Embedded or Qt/X11, both can
be successfully integrated with the Beagle board’s SGX GPU and the only
point of divergence in these instructions will be at (Qt) configure time
and the client side system (run time) configuration. Both implementations
offer window management, via QWS and X11 respectively, and operate at
around 27fps and 22fps respectively when running our hellogl_es2 example.
(16bit color depth at 1280×720)

I personally deploy Ångström on my Beagle board, it handles a large amount
of the logistics surrounding cross compilation and is generally very
agreeable, and these instructions are therefore going to be bolted to
Ångström for completeness. Feel free to establish an environment capable of
showing the OpenGL ES examples TI provide, then following the Qt level
considerations (Configuring Qt) accordingly.

For those holding a dormant Beagle board who are open to the author’s
distribution preferences:

Building the Ångström rootfs

Open Embedded is manifested in a git repository: in this posting we are
working within origin/stable/2009. Please follow the instructions give
here, they are comprehensive and got me completely off the ground.

http://www.angstrom-distribution.org/building-angstrom

These instructions end in you running:

bitbake base-image ; bitbake console-image ; bitbake x11-image

which actually builds an X11 angstrom image for your Beagle board. Please
note, you will need to build the X11-image if you want to build and deploy
the SGX packages (we will do this in the next section) via Ångström as opkg considers
X11 to be a required dependency of libgles-omap3_3.00.00.09. This is due
to one of the encapsulated windowing system libraries being X11 centric:

libpvrPVR2D_X11WSEGL.so

Regardless of the indicated X11 dependency, this package will bestow the required
kernel module on you for general OpenGL ES usage (console or X11). We will be
building our own QWS centric (libpvrPVR2D_X11WSEGL.so equivalent) library
behind the scenes for QWS in the Qt/Embedded instructions given later.

Ångström SGX integration

You now need to integrate the SGX drivers on your Ångström system.

You need to get your paws on:

OMAP35x_Graphics_SDK_setuplinux_3_00_00_09.bin

with the following MD5 checksum:

e15147ad76ddbe7c5aec682f5455b774

Getting this involves following the above link and going through the required registration/request process.
Once you have this file, you drop it in:

$OETREE/openembedded/recipes/powervr-drivers/libgles-omap3

and then run:

bitbake libgles-omap3-3.00.00.09

which generates the following packages:

libgles-omap3_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-dbg_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-demos_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-dev_3.00.00.09-r1.1_armv7a.ipk
libgles-omap3-tests_3.00.00.09-r1.1_armv7a.ipk

Deploy the x11-image to an sd-card, and copy these packages to the sd-card
for deployment on the target. If your beagle board does not have internet
access you will probably also require:

*  devmem2
*  libx11-6 (Only if you insisted on using a console build!)

as opkg will not be able to automatically install the required dependencies
from its repositories and you would hit the following error at deployment:

———————————————-
root@beagleboard:/opt/deploy# opkg install ./libgles-omap3_3.00.00.09-r1.1_armv7 a.ipk
Installing libgles-omap3 (3.00.00.09-r1.1) to root…
libgles-omap3: unsatisfied recommendation for libgles-omap3-tests
Collected errors:
* ERROR: Cannot satisfy the following dependencies for libgles-omap3:
*  devmem2 *  libx11-6 (>= 1.1.5) *
———————————————-

Once you have installed all the above packages, please reboot the board.

Your bootargs in U-Boot should look something like:

console=ttyS0,115200n8=noinitrd ip=dhcp rw root=/dev/mmcblk0p2 omapfb.mode=dvi:1280×720MR-16@60

assuming you want to output via DVI and are running a similar kernel
version (2.6.29-omap1 on my beagle) which accepts the same kernel
arguments indicated in the bootargs variable above.

Please note that we are specifying a 16 bit color depth which is intentional
and discussed in the “color depth considerations” section in the appendix

Please run the powervr demos (under X11) to establish that your drivers are
successfully installed and usable.

Configuring Qt

In order to build Qt now, all that is required for each target is an
appropriate mkspec:

For Qt/X11

You would fork your mkspec off the linux-g++ mkspec, the resulting mkspec’s
qmake.conf would resemble:

==================================================================
………….
include(../common/linux.conf)

# modifications to g++.conf
# These release optimization flags are TI supplied
# and a little more aggressive than Qt standard (gentoo types rejoice!)
QMAKE_CFLAGS_RELEASE     = -O3 -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp
QMAKE_CXXFLAGS_RELEASE     = $$QMAKE_CFLAGS_RELEASE

QMAKE_CC         = $FULLY_QUALIFIED_COMPILER_PREFIX-gcc
QMAKE_CXX         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK_SHLIB     = $FULLY_QUALIFIED_COMPILER_PREFIX-g++

# modifications to linux.conf
QMAKE_LIBS_EGL         = -lEGL -lIMGegl -lsrv_um
QMAKE_LIBS_OPENGL_QT     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um
QMAKE_LIBS_OPENVG     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um -lOpenVG -lOpenVGU

QMAKE_INCDIR         = $TARGET_STAGING_PATH/usr/include
QMAKE_LIBDIR         = $TARGET_STAGING_PATH/usr/lib

QMAKE_AR         = $FULLY_QUALIFIED_COMPILER_PREFIX-ar cqs
QMAKE_OBJCOPY         = $FULLY_QUALIFIED_COMPILER_PREFIX-objcopy
QMAKE_STRIP         = $FULLY_QUALIFIED_COMPILER_PREFIX-strip

load(qt_config)
==================================================================

and you would configure Qt with:

configure -arch arm -xplatform linux-omap3-g++ -opengl es2 -openvg

all that remains is to adjust /etc/powervr.ini on the target to be:

[default]
WindowSystem=libpvrPVR2D_FLIPWSEGL.so

Now compile an example, eg:

./examples/opengl/hellogl_es2

deploy it and Qt to the target and enjoy.

For Qt/Embedded

Since we don’t have the X11 abstraction, we have to interface with the
underlying hardware/interfaces with Qt/Embedded’s gfx abstraction layer. We
are going to be making some heavy use of the powervr driver resident under:

$QTSRCTREE/src/plugins/gfxdrivers/powervr

there is a README file in the powervr directory that is definitely
recommend reading, and lends some serious insight into our powervr driver
and Qt/Embedded in general. The same driver is used for MBX/SGX targets and
hence sees a fair amount of usage on a variety of target devices.

You would fork your mkspec off the qws/linux-arm-g++ mkspec, the resulting mkspec’s
qmake.conf would resemble:

==================================================================
…………….
include(../../common/qws.conf)

# modifications to g++.conf
QMAKE_CFLAGS_RELEASE     = -O3 -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp
QMAKE_CXXFLAGS_RELEASE     = $$QMAKE_CFLAGS_RELEASE

QMAKE_CC         = $FULLY_QUALIFIED_COMPILER_PREFIX-gcc
QMAKE_CXX         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK         = $FULLY_QUALIFIED_COMPILER_PREFIX-g++
QMAKE_LINK_SHLIB     = $FULLY_QUALIFIED_COMPILER_PREFIX-g++

# modifications to linux.conf
QMAKE_INCDIR         = $TARGET_STAGING_PATH/usr/include
QMAKE_LIBDIR         = $TARGET_STAGING_PATH/usr/lib

QMAKE_LIBS_EGL         = -lEGL -lIMGegl -lsrv_um
QMAKE_LIBS_OPENGL_QT     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um
QMAKE_LIBS_OPENVG     = -lEGL -lGLESv2 -lGLES_CM -lIMGegl -lsrv_um -lOpenVG -lOpenVGU

QMAKE_AR         = $FULLY_QUALIFIED_COMPILER_PREFIX-ar cqs
QMAKE_OBJCOPY         = $FULLY_QUALIFIED_COMPILER_PREFIX-objcopy
QMAKE_STRIP         = $FULLY_QUALIFIED_COMPILER_PREFIX-strip

#These defines are documented in the powervr README, please read it
DEFINES += QT_QWS_CLIENTBLIT QT_NO_QWS_CURSOR

load(qt_config)
==================================================================

and you would configure Qt with:

/opt/dev/source/qt-beagle-4.6/configure -embedded arm -little-endian -xplatform qws/linux-omap3-g++ -opengl es2 -openvg -plugin-gfx-powervr

all that remains is to adjust /etc/powervr.ini on the target to be:

[default]
WindowSystem=libpvrQWSWSEGL.so

Now compile an example, eg:

./examples/opengl/hellogl_es2

deploy it and Qt to your board, and after shutting down X, run the example with
the following arguments:

./hellogl_es2 -qws -display powervr

-qws - starts the application as the QWS server with exclusive access to the
system hardware which manages all subsequent Qt “client” applications

-display powervr - indicates that Qt should use the powervr driver we
compiled earlier

Summary

I hope that this posting encourages people to go forward and experiment
with a fully accelerated Qt 4.6 on the beagle board. Offloading the
painting work onto the GPU drastically reduces the load on the CPU and
broadens the range of applications which can feasibly be run on this
broadly available (cheap!) embedded hardware. The Beagle board has
really nice hardware, and it would be infinitely useful for us to have external
people using our powervr driver and getting it as broadly used/refined as
possible.

Appendix

Additional Benefits to OpenGL ES acceleration

If you take any Qt Graphics View based example and set a QGLWidget as its
viewport, a large amount of work will be offloaded on the GPU leaving your
CPU free to frolic. To put this in perspective, a modified version of:

./examples/animation/animatedtiles

which continually transitions runs smoothly at 720p on the beagle board
when using software, but consumes 100% CPU time according to top (99.3% to
be fair). It is therefore CPU bound and you are not going to be doing
anything else in the background.

When backed by a QGLWidget, the CPU usage drops to 20% on the exact same
example in the exact same conditions (720p, at 16bit color depth). The
frame rate suffers slightly, but at least this is mandated by the GPU

Minor clipping issue evident in hellogl_es2

The bubbles are evidently clipped on the right hand side, I will hopefully
beat you to reporting this at: http://bugreports.qt.nokia.com/secure/Dashboard.jspa

I have not seen any other artifacts, please file any additional bugs you
may encounter at the above URL.

Are these instructions applicable to OMAP3 targets in general

Yes. There is no theoretical reason these instructions would not suffice
for any OMAP3 based target, although I have not personally verified them
outside of Beagle board usage. Caveat emptor.

No Scratchbox2 usage when cross compiling

The more astute of your would recognize that I bypassed Scratchbox2 when
configuring Qt/X11 this time around. I payed dearly for it, and this X11
build has no fontconfig, dbus or glib support even though the Ångström
subsystem I am building against has support for all of them. If you want a
full fledged X11 build with decent font support and OpenGL ES support,
please either:

1) Invest your time in physically adjusting your MKSPEC (and/or wrestling
pkg-config) to get all desired dependencies detected and built against

-Or-

2) Take the easy road, refer to my previous blog posting “Cross compiling
Qt/X11″ and merge the above mkspec changes into the:

./mkspecs/unsupported/linux-scratchbox2-g++

mkspec in your Qt 4.6 source tree.

The same goes for Qt/Embedded which is more self sufficient, but which will
be built without dbus, glib, etc and additional external dependency support
without additional mkspec/environment modification or the use of Scratchbox2
to abstract this away.

Color depth considerations

1) The powervr implementation we are relying on does not support
PVRSRV_PIXEL_FORMAT_RGB888 (24bit color depths), it does however support
PVRSRV_PIXEL_FORMAT_RGB565 and PVRSRV_PIXEL_FORMAT_ARGB8888

2) Ångström is busybox based, and the fbset command you will need to set 32
bit color depths on the console will not work with the default fbset
busybox symlink. You will therefore have to install and use fbset(.real)
in order to get 32bit color depths, which is a simple opkg install away for
the connected Beagle board and a bitbake away for the stranded.

Please note the color depth specified in the boot arguments

console=ttyS0,115200n8=noinitrd ip=dhcp rw root=/dev/mmcblk0p2 omapfb.mode=dvi:1280×720MR-16@60

if you want 32 bit color depth, use:

console=ttyS0,115200n8=noinitrd ip=dhcp rw root=/dev/mmcblk0p2 omapfb.mode=dvi:1280×720MR-24@60

followed by:

/usr/sbin/fbset.real -depth 32 -rgba 8/16,8/8,8/0,8/24

after your Linux kernel drops you in userspace with a kiss on the cheek. A
brave man once tried leaving the color depth at 16 in his boot args, and
jumping all the way to 32bit with fbset so he could change between the more
performant 16 bit color space and the hardware compositing ARGB offering.
Running the dedicated fbset command halved his vertical resolution
regardless of any other parameters he tried to pass fbset and he eventually
ran off to fight another day.

There is a clear performance hit of 7 fps when running hellogl_es2 in
32bit rather than 16bit, taking you down to 20 fps. This hit is even more
pronounced when setting a QGLWidget on the viewport of a QGraphicsView. I
am not sure who is responsible for this, and will be personally
investigating it in the future. Any conjecture/feedback/research performed
by the reader would be greatly appreciated.

*Edited: Introduce rudimentary formatting to make the blog look less Vim forged

warwick
Qt
Embedded
Posted by warwick
 in Qt, Embedded
 on Thursday, October 15, 2009 @ 05:34

Today marks the 10th Birthday of Qt Embedded! It was 10 years ago today that we first came up with the notion of an “embedded” version of Qt to serve the industrial sector and the infant higher-end handheld/CE market. At the time, the project was called “Qt/FB” (Qt for FrameBuffers).

This first version of Qt Embedded was built around the idea of a QPaintDevice for QImage. This notion (through multiple rewrites) eventually developed into some of the biggest architectural improvements in cross-platform Qt: generalized paint engines (the raster paint engine being the “frame buffer” one); window surfaces/backingstore; and Alien (non-native child widgets). These were critical improvements that then opened the door for easier platform porting (Mac OS X and Symbian/S60 benefit much from them), and accelerated paint engines, and now graphics systems, for OpenGL and OpenVG.

From simple beginnings on iPAQ and Cassiopeia handhelds and industrial devices, then, as the foundation for Qtopia, on the Zaurus and eventually phones like the Greenphone and the Neo and various cool consumer electronics devices (some of which we could never tell you about), Qt Embedded functionality was ever richer.

Embedded targets have changed a lot in 10 years - OpenGL ES is now commonplace, and the “PDA” has been completely hybridized into mobile phones. Touch screen quality and user-expectations for beautiful fluid interfaces now well-exceeding the demands on the desktop, creating ever more challenges.

We have learned a huge amount in this time about what it takes to put Qt on the “low end”. Paul’s recent blog entry about Lighthouse shows how the learning is still bubbling away, and with Qt for Symbian S60, Qt for Windows CE, and Qt for X11 on Maemo devices, the low end will of course remain a very important focus for us, with performance in all parts of Qt a key concern - bringing benefits to all Qt platforms, including the desktop.

Paul Olav Tvete
Qt
Lighthouse
Embedded
Posted by Paul Olav Tvete
 in Qt, Lighthouse, Embedded
 on Friday, October 02, 2009 @ 14:16

Even if this is my first blog post, some of you may have seen my name before. I have been with Trolltech and Nokia since 1996 (which makes me senior surviving Troll), and I am here to introduce a little research project we are starting up.

As you all know, our motto is “Qt Everywhere”, and we would love to see Qt run on all the cool devices that are coming out these days, but the problem is that making a port from scratch is hard work: Qt ports generally contain tens of thousands of lines of code, and require intimate knowledge of Qt internals.

One way to port with less effort is to use Qt for Embedded Linux, which provides functionality for adapting to different graphical devices. Unfortunately, doing this is not always trivial. Today I will talk about something that might make things easier, but first a little historical background information:

Qt for Embedded Linux (or Qt/E for short) has been with us now for about 10 years (the Qt/FB project started around 15 October 1999), and it’s still going strong, powering everything from small hand-held devices to large industrial machinery. However, times move on, and we are seeing new types of hardware that are very different from what we envisioned 10 years ago.

While Qt/E still remains amazingly flexible, sometimes it starts to feel like a little too much work to port it to some systems. Qt/E
includes its own Q Windowing System (QWS), and this is not always relevant, especially for systems that already includes window system functionality, or features that make it possible to implement windowing in ways we didn’t foresee 10 years ago.

We have been looking at ways to refactor Qt/E so it no longer depends on QWS, but there is a lot of legacy there, and over the years knowledge of QWS has infiltrated large portions of the Qt/E codebase. Getting QWS out of Qt/E was starting to look like a major project.

Then, one day, Rhys came up with the idea of starting from the other direction. How difficult would it be to just stub out all the
platform-specific parts of Qt and get a completely new port to compile? Given that most of the infrastructure is already in place
thanks to the raster paint engine and Alien, it should then be fairly easy to get a single process to show a full-screen window on the framebuffer. After talking it over with Rhys, I was starting to hope that this could help with the QWS problem as well, but of course we needed to try it out to see if it was actually feasible.

Rhys had something compiling in less than a week, and we had pixels on screen the next day.

We then played around with it for a couple of weeks, getting most of the crashes out of the system, as well as adding a few more back-ends that showed that we could support slightly more complex behavior.

Then we had to start concentrating on the upcoming 4.6.0 release for a while. However, word started spreading around, and people from all over were asking questions and found out that this could be the perfect thing for their pet project. Therefore, we realized that it’s about time to show off the results of our little feasibility study.

The most important thing for a project is of course a code name, and we decided on Lighthouse [not to be confused with a very early preview of Qt for S60 that was used by about 5 people outside Nokia…] since this meant we didn’t have to change the Q_WS_LITE platform define.

And of course, the obligatory screenshot. This one’s made using the “testlite” back-end:

Screenshot

Boring, right? It looks just like Qt… The point about Lighthouse is how easy it is to write a backend for new hardware. A more interesting picture would be to see how much code is needed to do that. Let’s look at the “minimal” backend, which is a complete example showing how to use a QImage as a display device:

~/git/qt-lighthouse/src/plugins/graphicssystems/minimal$ wc -l *
71 main.cpp
10 minimal.pro
70 qgraphicssystem_minimal.cpp
85 qgraphicssystem_minimal.h
101 qwindowsurface_minimal.cpp
73 qwindowsurface_minimal.h
410 total

410 lines of code is not too bad, but, wait a minute! That includes 40 lines of copyright header per file. Sloccount gives us a better impression:

Total Physical Source Lines of Code (SLOC) = 147

Now for something with a bit more meat to it: The OpenVG back-end clocks in at a SLOCcount of 288 lines, and it took about a day to write.

This is still early days, and very little is set in stone (or even properly documented), but you can check out the code, and see some very basic getting-started documentation at: http://qt.gitorious.org/+qt-developers/lighthouse

Just to make it very clear: this is a research project that is just starting out. Don’t assume that anything will work, or that any APIs
will stay the same for long. Count yourself lucky if it does not crash horribly and lock up your machine, or worse.

If you want to join in the fun, we can use the qt-embedded-interest@trolltech.com mailing list for development
discussions. I also hang around on #qt-labs as paulot from time to time.

Donald Carr
Qt
Embedded
Build system
Posted by Donald Carr
 in Qt, Embedded, Build system
 on Thursday, September 10, 2009 @ 00:49

Overview

Cross compiling Qt Embedded is relatively trivial since it is so self
contained, but as the number of external dependencies increases (DirectFB,
D-Bus, GStreamer, OpenGL ES) adjusting your custom mkspec to individually
account for the location of dependencies on the host machine becomes
increasingly tedious/untidy. This complexity culminates in cross compiling
Qt/X11 which adds the additional dependency of fontconfig/FreeType/X11 to
the fray.

This blog is intended as a general overview of the cross
compilation of Qt/X11 for embedded Linux targets. The wide availability of
the BeagleBoard and the proliferation of embedded Linux platforms gives us
the rare opportunity (and impetus) to walk people through the cross
compilation of Qt for an X11 target and get it up and running on a
reference embedded device.

These steps can be summed up as:

  1. Build a reference Linux image and toolchain (Ångström)
  2. Create an appropriate Scratchbox 2 target
  3. Build Qt against this reference image
  4. Reap the whirlwind

This walk through will introduce you to 2 separate tools intended to
simplify cross compilation for embedded targets:

OpenEmbedded (used to build the reference Linux system (Ångström) and toolchain)
Scratchbox 2 (used to build Qt/X11 against the reference system)

They both have their strengths and their particular uses, and if I offend
your sensibilities by using them in conjunction be sure to express yourself
with vigour in the comments section below. Neither tool is required to
achieve this goal, both tools expedite achieving the desired goal.

Building Ångström

I have personally chosen to use Ångström as a reference platform as the
Open Embedded development environment is relatively straightforwards to
setup in a standard (K)Ubuntu Jaunty environment, supports both x86 and
x86_64 host machines, and because it provides a fairly minimalist Linux image
possessing everything required to build a full fledged version of Qt/X11
(X11, D-Bus, GStreamer, Glib, fontconfig, FreeType). Anyone from a Gentoo
background will also enjoy the reassuring quality of 9000 build steps
constructing your eventual Linux system from source.

I followed the instructions given here:

http://www.angstrom-distribution.org/building-ångström

which culminate in the following build step.

bitbake base-image ; bitbake console-image ; bitbake x11-image

I would personally recommend rather running:

bitbake beagleboard-demo-image

which builds an appealing E17 image and which meets all Qt/X11’s needs.

The resulting Linux images are immediately deployable and you will have
acquired a very recent (by cross compiler standards) gcc toolchain to use in
the next step

Creating an appropriate Scratchbox2 target

Scratchbox enables you to abstract away the host machine when cross
compiling for a target. Rather than having to correct for host paths, you
can simply execute certain commands in a chrooted environment which
directly resembles the desired targets layout with the targets headers/libs
in their anticipated locations. With Scratchbox 2, you simply prefix
toolchain calls with sb2, and they are run within the specified
realm/sandbox.

Firstly, install Scratchbox 2 using your distributions package manager, or
via whatever mechanism you prefer. Next, you will need to create a suitable
Scratchbox 2 target. This involves executing “sb2-init” (from within the
staging/root directory containing the target’s /usr/include and /usr/lib)
with the following arguments:

  1. an appropriate cpu transparency command (normally qemu-$arch)
  2. the desired name of the target
  3. the fully qualified path of the gcc compiler

My sb2-init line looked like this:

sb2-init -c /usr/bin/qemu-arm angstrom-beagle /OE/angstrom-dev/cross/armv7a/bin/arm-angstrom-linux-gnueabi-gcc

and was run within:

/OE/angstrom-dev/staging/armv7a-angstrom-linux-gnueabi;

(Tip: The targets you have created and associated parameters are helpfully
revealed in subsequent calls to sb2-init)

Prior to running sb2-init as shown above, I personally had to modify:

/usr/bin/sb2-build-libtool

by explicitly adding “–host=x86_64″ to the configure line in order to get
libtool to compile successfully. The required diff would look something
like this (depending on your host):

- ./configure –prefix=$HOME/.scratchbox2/$TARGET –build=$(uname -m)-unknown-linux-gnu
+ ./configure –host=x86_64 –prefix=$HOME/.scratchbox2/$TARGET –build=$(uname -m)-unknown-linux-gnu

Cross compiling Qt/X11

Whenever you cross compile Qt you should create a custom mkspec based off
an appropriate reference mkspec, mkspecs/linux-g++ in this case. The
required modifications involve hijacking the qmake variables responsible
for defining all the target toolchain commands (gcc, g++, ar,
objcopy, strip) and prefixing each command with sb2.

My qmake.conf in my target mkspec looks like this:

=========================

#
# qmake configuration for linux-g++
#

MAKEFILE_GENERATOR = UNIX
TEMPLATE = app
CONFIG += qt warn_on release incremental link_prl
QT += core gui
QMAKE_INCREMENTAL_STYLE = sublib

include(../../common/g++.conf)
include(../../common/linux.conf)

# modifications to g++.conf
QMAKE_CC = sb2 gcc
QMAKE_CXX = sb2 g++
QMAKE_LINK = sb2 g++
QMAKE_LINK_SHLIB = sb2 g++

# modifications to linux.conf
QMAKE_AR = sb2 ar cqs
QMAKE_OBJCOPY = sb2 objcopy
QMAKE_STRIP = sb2 strip

load(qt_config)

=========================

Once you have modified this mkspec to address any additional considerations
you might have, you can export PKG_CONFIG_PATH to point to your targets
pkg-config (.pc) files, which are normally in a pkg-config directory under
the targets lib directory:

$targetPathOnHost/usr/lib/pkgconfig. Please note this path must be fully
qualified relative to the host)

Qt’s configure script currently does not employ pkg-config when
establishing FreeType library metainformation when testing for fontconfig
support, instead opting for heuristics which are explicitly excluded when
cross compiling. This rough little (unsupported) patch will resolve this,
and will result in the correct detection and compilation of Qt with
fontconfig/FreeType support.

=========================

diff –git a/configure b/configure
index 3f3e55a..54de96b 100755
— a/configure
+++ b/configure
@@ -5115,6 +5115,10 @@ if [ “$PLATFORM_X11″ = “yes” ]; then
if [ -n “$PKG_CONFIG” ] && $PKG_CONFIG –exists fontconfig 2>/dev/null; then
QT_CFLAGS_FONTCONFIG=`$PKG_CONFIG –cflags fontconfig 2>/dev/null`
QT_LIBS_FONTCONFIG=`$PKG_CONFIG –libs fontconfig 2>/dev/null`
+ if $PKG_CONFIG –exists freetype2 2>/dev/null; then
+ QT_CFLAGS_FONTCONFIG=”$QT_CFLAGS_FONTCONFIG `$PKG_CONFIG –cflags freetype2 2>/dev/null`”
+ QT_LIBS_FONTCONFIG=”$QT_LIBS_FONTCONFIG `$PKG_CONFIG –libs freetype2 2>/dev/null`”
+ fi
else
QT_CFLAGS_FONTCONFIG=
QT_LIBS_FONTCONFIG=”-lfreetype -lfontconfig”

=========================

then kick off the configure with:

./configure -arch arm -xplatform $customMkspecDirName -force-pkg-config

configure, make and pkg-config are being run directly on the host,
pkg-config is using the targets .pc files, the core tools (qmake, uic, moc)
are being built for the host, the config.tests are being correctly built
against the targets mkspecs and the cross compiler is used for all target
specific compilation. With any luck you with see a large number of the
configure tests pass, and see Qt configured to be built with full
fontconfig/GStreamer/D-Bus support. You can now build Qt by simple running
“make” (You are using the host machines Make, and please note that you
never actually need to prefix sb2 on the commands you run, the qmake
generated Makefile will contain sb2 calls where applicable)

Reap the whirlwind

Cross compiling Qt applications now simply involves running the freshly
built qmake against the desired project .pro file, and running make as per
usual. (You are using Qt tools built for the host, and the host system’s
make and pkg-config applications amongst other things). Running make
therefore results in the host system’s “make” proceeding through all
the build steps using the correctly prefixed build tools.

Assuming your build is dynamic, your libraries and plugins have to be
deployed to the prefix path you either implicitly or explicitly specified
at configure time)

(Disclaimer: I realize that there is no implicit dependence on Linux when
discussing X11, and there is nothing Linux centric in my instructions other
than that it is the reference (and host) platform. I am building a standard
Qt X11 build in a controlled environment advertising my headers/libs in
their canonical paths (via Scratchbox) and making use of qmake’s cross
compiling infrastructure. If you have a suitable root filesystem,
associated toolchain (cross compiler), and if both Qt/X11 and Scratchbox 2
support your target platform, you should be set (although officially
thoroughly unsupported) to walk down the yellow brick road with these
instructions.)

****Note:  As of Qt 4.6 the above mentioned scratchbox2 approach is redundant on systems with a fully functioning pkg-config and is only recommended as a fall back. Build the Ångström sub-system, export PKG_CONFIG_PATH and PKG_CONFIG_SYSROOT appropriately and configure should correctly establish the capabilities of the sub-system.



© 2008 Nokia Corporation and/or its subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation in Finland and/or other countries worldwide.
All other trademarks are property of their respective owners.