Qt/X11 bring up on Tegra2 with full OpenGL ES 2 support

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


Blog Topics:

Comments