Saturday, September 25, 2021

Qt 6 on the Raspberry Pi on eglfs

It has been some time since Qt 6 was released. Now that Qt 6.2 is almost out, I guess it is time to have a look at it.

Building Qt 6

Qt 6 moved from qmake to cmake. This makes a difference when trying to build it and cross-build it. Instructions on how to build are already available online from many sources, so I won’t repeat the theory here. I just want to note a few key points.

Configuration

I configured this build in the simplest form. To start, I want to use eglfs on OpenGL ES.

Toolchain

Building Qt requires a toolchain for building on the host and a toolchain to build for the target (the Raspberry Pi in this case). The toolchain from the host is typically provided by your distro (I used Manjaro in this case), while the toolchain to cross-build for the Raspberry Pi is officially provided here. In the past years I had a lot of weird problems building with those toolchains, so I started to create my own. Never had any problem anymore. Here you can find the toolchains:

  • Raspberry OS Stretch: here;
  • Raspberry OS Buster: here.

Please note that those toolchains are not always able to target every arch. The one for Buster is the one I used in my build, and the target arch is armv8-a.

Dependencies

Dependencies are already listed elsewhere. I would only like to note one thing here: I had problems linking because of a missing symbol: qt_resourceFeatureZstd. According to the sources, it seems that resources are compiled by the rcc tool. My guess is that the host tools use zstd by default to compress when available, but this is a problem when zstd is available on the host and not available on the target. Therefore, I suspect you have to decide if you want zstd support or not before building Qt 6 for the host, and be coherent with the build for the target. I decided to add zstd.

Build Errors

I had a few build errors building Qt 6.2 beta3. Nothing particularly relevant, but I had to apply a few changes. I did not keep track of those changes, they were all trivial.

Build Qt Test App

Once the Qt builds are ready, it is time to run. For the moment, I only want to do a quick test of QML. In my build, I forgot to set eglfs as the default platform, but it can be set it in the environment. I wrote a simple app to test Qt Quick here. The animations are very simple, but I wrote it like this to see how well many items are handled and how well the uniform movement on the y axis is rendered.

NOTE: Unlike Qt5, Qt6 includes host tools and tools built for the target. This means you can build the test app on the target directly or cross-build it from your host. For the package below anyway, you'd need to have a system compatible with those binaries.

First App

This video shows a comparison of this Qt 6 build against Qt 5. It also shows the same benchmark app on Intel UHD and nVidia.

Download

If you want to test the build of Qt 6 on your rpi, you can download it from here:

Download Qt 6.2.0-rc1 for Raspberry OS Buster armv8-a

The package does not include the toolchain, that you can download from the other links, but includes the host build. I don’t think it will be of help, as it is built for my Manjaro context, but I placed it there anyway.

The positions of the directories are relevant:
  • /opt/rpi/rpi-8.6.3: toolchain;
  • /opt/Qt-x64-6.2.0-beta3: host build;
  • /usr/local/Qt-rasp-6.2.0-beta3: position in the target;
  • /opt/rpi/sysroot: sysroot for cross-building.

Runtime Context

The is the 3D environment as seen by Qt 6:

qt.rhi.general: Created OpenGL context QSurfaceFormat(version 2.0, options QFlags<QSurfaceFormat::FormatOption>(), depthBufferSize 24, redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize 0, stencilBufferSize 8, samples 0, swapBehavior QSurfaceFormat::DefaultSwapBehavior, swapInterval 1, colorSpace QColorSpace(), profile  QSurfaceFormat::NoProfile)
qt.rhi.general: OpenGL VENDOR: Broadcom RENDERER: VC4 V3D 2.1 VERSION: OpenGL ES 2.0 Mesa 19.3.2
qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no.
qt.scenegraph.general: rhi texture atlas dimensions: 2048x2048

Bye 😉

Experimental Implementation of the Blog on a Raspberry Pi! 😉

I recently started to add many useful open source services to my Raspberry Pi, like Jenkins, GitLab etc… I wrote some articles about running some services on a arm64 device here:

After these, I also wanted to try WordPress: it is already available as a comfortable docker image for arm64. How could I put it to work? I thought I could reimplement the Bugfree Blog in WordPress!

Unfortunately it was a bit harder than I thought: first of all this bug was making the system completely unstable. I fortunately found a workaround soon by bisecting the kernel, and now there is also an official fix. The fix is not published yet on Ubuntu, but with this docker image I can apply the patches and cross-build the Ubuntu kernel quickly.

A second problem was related to disconnections of USB devices when USB hubs are connected. This is still unresolved.

A third problem is related to the SD card: I never had problems with the SD card, but I recently broke a few. The Raspberry Pi 4 is hotter that I thought, even when load is minimum. The SD cards are guaranteed to work properly up to 85°C, and the Raspberry Pi is set to that max temp, but I tried to reduce it by using a proper case and adding a little (and very professional) Lego castle to encourage heat dissipation. Let’s hope SD cards can live longer.

New URL

The new URL for the experimental Bugfree Blog on Raspberry Pi 64 bit is:


We’ll see if the experiment succeeds, what the performance is and how much I’ll keep it active.
If you are curious, have a look!
Bye 😉

Thursday, September 23, 2021

Docker Image for the Awesome MLDonkey Service

I really like this excellent piece of software. I found some docker images for it for the arm64 architecture, but they seemed not to be very up to date, so I created my own. Here you can find my version of a dockerized MLDonkey service, built for many archs: armv7, arm64, x86 and x64. The arm versions are perfect for Raspberry Pi variants.

The latest version of the image is taken from this commit, which is the latest at the time of writing. It also includes a couple of patches that I sent to add a dark theme.

The image is built on top of debian:buster. For the moment, it is difficult to use something newer because of this known issue.

  • Image on Docker Hub: link;
  • GitHub repo for the project: link.

To run it, you only need a single command:

$ docker run -i -t -v "`pwd`/data:/var/lib/mldonkey" carlonluca/mldonkey

For more options read the readme in the repo.

Bye! 😉

Sunday, September 19, 2021

Measuring the Frame Rate in Qt/QML

I frequently need to measure the frame rate in a Qt/QML application to have an idea of how heavy the changes I'm making are. In the past, I found two approaches that seemed to answer the question: one is using a simple QML item, measuring the frequency of changes of a property. The other is using a custom QQuickItem, measuring the frequency of the calls received to refresh it. I never used the first approach because it did not feel safe, while I typically used the second.

Instead of copy/pasting code into my projects repeatedly, I thought I could add it to my collection of simple procedures in https://github.com/carlonluca/lqtutils, making it simple to integrate when needed. I therefore asked myself which one to include.

By thinking a bit about it, I thought of a different simpler approach using the signal QQuickWindow::frameSwapped(). This is what Qt doc says about it:

This signal is emitted when a frame has been queued for presenting. With vertical synchronization enabled the signal is emitted at most once per vsync interval in a continuously animating scene. This signal will be emitted from the scene graph rendering thread.

This seemed a reasonable approach, simple to implement, very concise and lightweight. The resulting code is in the repo. Doc is in: https://github.com/carlonluca/lqtutils#lqtutils_uih.

Is this Correct?

I was wondering if my approach was correct, so I thought I could compare with the other approaches. I took the snippets from this SO question. I tried the three techniques separately and also tried to add them together in the same code for a comparison of the values. For the test I used my QML app here: https://github.com/carlonluca/Fall. In the branch https://github.com/carlonluca/Fall/tree/fps_comparison I added all the components to compare. This is the result:


As it can be seen, the method based on the QQuickPaintedItem gives the same result of the one based on the frameSwapped() signal. The other one is very different. The explanation for this is probably based on the fact that the Qt scene graph on Linux renders through the threaded render mode. In fact, forcing a single-threaded render mode makes the three techniques agree on the measurement (second run in the video).

Compared to a custom QQuickPaintedItem, the frameSwapped() technique seems to be more lightweight, so it is the one I implemented in my repo.

Bye! ;-)

Wednesday, September 8, 2021

Using requirejs in WordPress posts

While porting this blog to WordPress as an experiment, I came across a pretty frequent problem: using requirejs in a WordPress post. In my case, requirejs is needed to use my TypeScript libraries from https://github.com/carlonluca/isogeometric-analysis in the post, to create the plots you see in this post.

It was not simple at all to use it in Google Blogger, WordPress does not seem to behave very differently in this regard. When the post is rendered, I get errors like:

Uncaught Error: Mismatched anonymous define() module: […]

Uncaught Error: Mismatched anonymous define() module: […]
This may be related to the fact that something in WordPress or its plugins looks for that symbol and gets confused when another one is defined in the post. I found many pages treating this problem, but no solution satisfied me, either because it did not work or because I did not like it. I’d prefer the solution to be entirely contained in the post itself, I won’t probably use requirejs often.
This is the way I solved the problem: let’s give the time to WordPress and all its plugins to load and settle. Then, start loading requirejs and all the other deps we need in a script. This is an example for my specific use case:

window.addEventListener("load", function() { $.getScript('https://requirejs.org/docs/release/2.3.6/comments/require.js', function() { $.getScript('https://carlonluca.github.io/isogeometric-analysis/dist/bundle.js', function() { require(["nurbs/drawNurbsCurveExample"], function(d) { d.drawNurbsCurveExample1("nurbsCurve1", true) d.drawNurbsCurveExample2("nurbsCurve2", true, "nurbsBasis2") d.drawNurbsCurveExampleCircle("nurbsCurve3", true, "nurbsBasis3") }) require(["nurbs/drawNurbsSurfExamples"], function(d) { d.drawNurbsSurfPlateHole("nurbsSurf1", true) d.drawNurbsSurfToroid("nurbsSurf2", true) }) }) }) }, false)

To do this, I used jQuery. So, first of all jQuery is loaded. Then, on the onload event, I load requirejs. When requirejs is loaded, I then load my library, which needs requirejs, and then I can freely use it in the post. Note that simply adding script elements was not sufficient, the order must be preserved and the callbacks must be used to ensure the proper chain is respected.
This approach is a little verbose, but allows me to leave the rest of the theme unchanged and confines the mess to the specific posts needing these structures.

Saturday, August 21, 2021

Cross-building the Ubuntu Kernel for the Raspberry Pi 4 (arm64)

I recently had to rebuild the Ubuntu kernel for the Raspberry Pi pretty often to apply some patches. Building on the Pi is simple, but takes A LOT of hours and completely saturates the rpi4. Also, it means installing many dev packages, which I do not typically need. I also tried to do it on a development rpi3: took many hours, failed a few times because of insufficient RAM etc… It is a pain.

I therefore decided to try to cross-build it from my machine, which is not a Ubuntu machine at the moment. Quickest and simplest way I found is to use Docker. The result seems to work, so I decided to also provide the tools I created for myself here: https://github.com/carlonluca/docker-rpi-ubuntu-kernel.

Usage

The image only contains the tools and the libs needed to compile. The kernel itself and the script is provided externally. A workspace directory will contain both the kernel code to build and the output debian packages. With the following command the script is executed in the container and you should get your debs:
docker run --rm -it --name builder -v $PWD/workspace:/workspace \
    -v $PWD/build.sh:/workspace/build.sh carlonluca/docker-rpi-ubuntu-kernel:focal \
    /workspace/build.sh
The workspace directory must contain a src directory with the kernel, so you’ll have to create it yourself and then patch your kernel:
mkdir workspace
cd workspace
git clone https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux-raspi/+git/hirsute src
[apply needed patches]
The resulting packages can then be moved to the pi and installed with:
sudo dpkg -i *.deb
Hope this tool can be useful! Bye ;-)