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

Published Friday February 5th, 2010
15 Comments on Qt/X11 bring up on Tegra2 with full OpenGL ES 2 support
Posted in Build system, Embedded, OpenGL

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

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Build system, Embedded, OpenGL

15 comments

ezjd says:

I am wondering what components are involved in X11 for this OpenGL support:
1) Qt -> Xserver (through fbdev?) and Qt -> Tegra OpenGL lib directly
OR
2) Qt -> Xserver ( -> GLX -> DRI -> Tegra DRI driver -> Tegra OpenGL lib)
Seem the 1) applies, however, I suspect that when Qt OpenGL app is running, it has to be full screen, i.e. no window management from X11. I heard that this is “embedded” way to do OpenGL but I don’t think Maemo 5 on N900 behaves the same (My guess is the 2) is used).

Apparently, the 2) has some more overhead involved but it provides more integration with X11 and what I am curious is whether it is difficult to write a DRI driver with an existing Tegra OpenGL lib.

Great article! I’m up and running after following your directions.

A few things I had to work around: building from the 4.6 and 4.6-stable branch failed for me with:

In file included from ../../include/QtOpenGL/QtOpenGL:6,
from gl2paintengineex/qglgradientcache_p.h:55,
from gl2paintengineex/qglgradientcache.cpp:45:
../../include/QtOpenGL/qglbuffer.h:1:40: error: ../../src/opengl/qglbuffer.h: No such file or directory

Not sure if this was my doing or something in flux on those branches, but master built fine.

Also, for anyone wanting to output on a display other than VGA, see the burnflash instructions for passing -d … you need to flash your board for a specific display-type (e.g. HDMI) before it will be accessible via X. This is more of an Nvidia thing than a Qt thing, but it was a little buried so I thought I’d share it.

Now on to getting better fonts installed and figuring out why QPainter draws funny things when rendered via OpenGL. Also, my QPixmap-based brushes don’t show up. I saw the same artifacts (save the latter, which is unique to this build) on my workstation when running with -graphicssystem opengl so this may just be the state of things. I may try building with the raster paint engine, if that’s feasible on this platform… though I imagine that would give up most/all acceleration.

Many thanks for a great walkthrough!

Donald Carr says:

@ezjd: To the best of my knowledge the hierarchy is:

Qt -> OpenGL ES 2 -> EGL -> X

This looks a little arse about face and I welcome corrections, but the path above is: Qt using its OpenGL ES 2 paint engine to render to a surface provided by EGL and managed by X11.

@Michael:

I am using the Qt 4.6 git branch, and have not hit similar issues. Are you sure you are not being bitten by symlink/syncqt header location logistic issues? Headers should certainly not be missing (we have cascading branches to make sure this kind of thing never emerges into the wild) and the snap prognosis is that your build dir/source tree is muddled.

Please report any bugs you see in our OpenGL (ES) engine at:

http://bugreports.qt.nokia.com/secure/Dashboard.jspa

All the -graphicssystem configure flag does is set the default graphics system, and this can be adjusted on X11 by passing the “-graphicssystem foo” argument or programmatically through QApplication::setGraphicsSystem ( const QString & system ). Raster is available on all platforms, and you do lose all hardware acceleration in favor of correctness. Qt’s raster engine is pretty fast though, and far faster than Qt’s X11 paint engine on most targets. How this changes with the acceleration of the underlying X backend is any mans guess, but my money is on raster.

When targeting embedded devices, I configure Qt to use the raster engine as default. I then set QGLWidget’s on the viewport of QGraphicsViews I wish to implicitly accelerate through OpenGL ES2. This will not help if your are trying to use our OpenGL ES 2 paint engine to render outside of a graphics view, in which case you want to use the above mentioned approaches to explicitly select the OpenGL paint engine, but is generally a good rule of thumb.

Once I confirm that the things I’m seeing are bugs in Qt, I’ll file some reports; in the meantime I’m still figuring out what’s what. I will also re-try on 4.6; since I was able to build master just fine I figured my source tree wasn’t too muddled but it’s quite possible.

I did try using -graphicssystem raster and surprisingly things looked about the same, and I noticed some speedups in the animated portions of my display. I suppose the speedups are not too surprising since I’m doing 2-D things which might suffer in the translation to GLES (I’m not optimizing how/when I switch painting states, probably causing shader reloads unnecessarily among othe things), but I was hoping to see things in full fidelity. I do have “Painter not active” messages coming out so I think my code for rendering into the QPixmaps that I use for brushes may be suspect… will look into that more.

Thanks again…

ohmy says:

Hi,

Interesting, being working on this board few weeks ago. Could you please share your knwoledge about ‘EGL->X’. As far as i know dri interface isn’t compliant with OpenGLES 1.x nor with 2.x and all the efforts like http://www.freedesktop.org/wiki/Xegl was simply http://www.freedesktop.org/wiki/Software/Xgl. I’d really like to know how it works.

Thanks

Donald Carr says:

As an indication of stability/performance the Tegra2 target has been persistently running an automated demo involving heavy blitting and transformation on a QGLWidget fronted QGraphicsView at 1080p for the past 3 days and is still going strong at ~30 fps

DrOctavius says:

Donald,

Thanks for this article about Tegra2.

I’m just wondering if there is any 3D benchmark against omap35xx.

Is really noticeable the difference, lets say.., compared to the beagleboard?

Donald Carr says:

We are aware of a need for concrete benchmark figures for different accelerated platforms and are assessing our options.

At a purely anecdotal level, I would have to see the Tegra2’s performance is far closer to that of my notebooks gpu (Nvidia Quadro FX 770m) than it is to the performance of the embedded targets I am familiar with. The performance in question is as gauged against a common (DirectFB friendly blit heavy) demo we run on all of our mainstream targets internally.

To follow-up on my build and brush issues: running syncqt made the 4.6 branch build fine, and the QPixmap-based brushes were only broken because libqjpeg wasn’t loading (due to my deploying only the libs, not the plugins). So my code runs fine and looks identical under ES2 and raster.

tsenyk says:

If anyone got something like that:
In file included from ../../include/QtGui/private/qapplication_p.h:1,
from /home/tsenyk/qt/qt/src/opengl/qglpixmapfilter.cpp:57:
../../include/QtGui/private/../../../../qt/src/gui/kernel/qapplication_p.h:529: error: expected identifier before numeric constant
../../include/QtGui/private/../../../../qt/src/gui/kernel/qapplication_p.h:529: error: expected ‘,’ or ‘…’ before numeric constant

add:
#undef CursorShape
to the other “#undef”s

Ang81 says:

Hi.

My problem is:

host-g++ -o “/opt/devlite/BKUP_16FEB/workdir/x11-maemo/bin/qmake” project.o property.o main.o makefile.o unixmake2.o unixmake.o mingw_make.o option.o winmakefile.o projectgenerator.o meta.o makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o borland_bmake.o msvc_dsp.o msvc_vcproj.o msvc_nmake.o msvc_objectmodel.o symmake.o initprojectdeploy_symbian.o symmake_abld.o symmake_sbsv2.o qtextcodec.o qutfcodec.o qstring.o qtextstream.o qiodevice.o qmalloc.o qglobal.o qbytearray.o qbytearraymatcher.o qdatastream.o qbuffer.o qlist.o qfile.o qfsfileengine_unix.o qfsfileengine_iterator_unix.o qfsfileengine.o qfsfileengine_iterator.o qregexp.o qvector.o qbitarray.o qdir.o qdiriterator.o quuid.o qhash.o qfileinfo.o qdatetime.o qstringlist.o qabstractfileengine.o qtemporaryfile.o qmap.o qmetatype.o qsettings.o qlibraryinfo.o qvariant.o qvsnprintf.o qlocale.o qlinkedlist.o qurl.o qnumeric.o qcryptographichash.o qxmlstream.o qxmlutils.o
The EGL functionality test failed!
EGL is required for OpenGL ES to manage contexts & surfaces.
You might need to modify the include and library search paths by editing
QMAKE_INCDIR_EGL, QMAKE_LIBDIR_EGL and QMAKE_LIBS_EGL in
/opt/devlite/BKUP_16FEB/workdir/x11-maemo/mkspecs/linux-g++.

Trying to add in /mkspecs/linux-g++/qmake.conf:

QMAKE_INCDIR_EGL =/opt/devlite/emPower-devlite-p1138/targetfs/usr/include/EGL/
QMAKE_LIBDIR_EGL =/opt/devlite/emPower-devlite-p1138/targetfs/usr/lib
QMAKE_LIBS_EGL =/opt/devlite/emPower-devlite-p1138/targetfs/usr/lib

I obtain the same errors.

Thanks in advance
@ng81

lee tong says:

Thanks for this article about Tegra2.

Donald Carr says:

@ang81:

QMAKE_LIBS_EGL is meant to be a complete link line, not just a library directory. If you go into config.tests and look at the egl tests egl.pro file, you can see where these variables are used in that file, and how they are included in the qmake generated Makefile.

I found the default link line worked perfectly for me in Qt 4.6.* when using the generic mkspecs/linux-g++ within scratchbox. Deviating from this path will require the above link line tweaking.

Donald Carr says:

The only known issue (out of the box) with Nvidia, the 32bit color depth segfault, has been isolated and was due to a perceived mismatch of EGL configs to X visuals in existing Qt code. This issue is discussed at length here:

http://bugreports.qt.nokia.com/browse/QTBUG-9444

If you know of other issues with Qt on Tegra2 or Qt on any other embedded platform, please report them!

When I first isolated this issue, I worked around it by explicitly setting a QGLFormat with an alpha channel. The bug aboves discusses the issue at hand and more elegant work arounds.

yybing says:

Hi,
I want to configure the QT4.6.2 with ./configure -prefix /opt/qtarm4 -arch arm -platform /qws/linux-x86-g++ -xplatform /qws/linux-arm-g++ -depths 16,24,32 -no-mmx -no-3dnow -no-sse -no-sse2 -no-glib -no-cups -no-largefile -no-accessibility -no-openssl -no-gtkstyle -qt-mouse-pc -qt-mouse-linuxtp -qt-mouse-linuxinput -plugin-mouse-linuxtp -plugin-mouse-pc -fast .

Then I get the following result:
Basic XLib functionality test failed!
You might need to modify the include and library search paths by editing
QMAKE_INCDIR_X11 and QMAKE_LIBDIR_X11 in /home/davinci/staging/mkspecs//qws/linux-arm-g++.

When I go into the config.tests/x11/xlib directory and exec make commond, then I get the following result:

xlib.cpp:42:22: error: X11/Xlib.h: No such file or directory
xlib.cpp: In function ‘int main(int, char**)’:
xlib.cpp:46: error: ‘Display’ was not declared in this scope
xlib.cpp:46: error: ‘d’ was not declared in this scope
xlib.cpp:46: error: ‘NULL’ was not declared in this scope
xlib.cpp:46: error: ‘XOpenDisplay’ was not declared in this scope
xlib.cpp:47: error: ‘XCloseDisplay’ was not declared in this scope

And I’m sure I have installed the libX11-dev, and I can find the file Xlib.h in /usr/include/X11.

Could you give some help?
Thanks in advance

Commenting closed.

Get started today with Qt Download now