Volunteering free build system capacity for science

One early morning a couple of weeks back, a question appeared on our company-internal chat:


Do we want to harness the idle CPU time of our hosts to benefit understanding the COVID-19 virus? Our CI hosts alone would throw in 2640 cores into the pool. https://foldingathome.org/2020/03/15/coronavirus-what-were-doing-and-how-you-can-help-in-simple-terms/

QML Hot Reload with Felgo Live for Qt

Beginning with the latest release of Felgo 3.4.0, developers can use QML Hot Reloading in their Qt and Felgo projects. This is a major step forward from QML Live Reload, available with the previous versions. Here are a few things you should know about QML Hot Reload, and how you can use it to speed up your development massively.

The Beauty of Qt and QML

Qt, at its core, is a C++ framework. This has a lot of advantages regarding stability and performance. On the other hand, developing with C++ can be more challenging compared to other languages. The great thing about Qt is that it combines the best of both worlds, with the additional language QML.

QML is a declarative language, that makes defining user interfaces and their behavior really easy and intuitive. It also allows you to use JavaScript to add your logic, without ever touching C++. And for any very performance-critical task, or e.g. to integrate other libraries, it offers you fall back to C++ and even down to native code for your target platform.

Make the Most of QML with Hot and Live Reload

Another advantage of QML is that it does not require a compilation step. For running apps it will be compiled JIT (just in time) and even AOT (ahead of time) to improve performance, but this is not mandatory for the language itself. And this is where Live and Hot Reloading comes into play.

QML Hot Reload with Felgo Live allows you to change your QML & JavaScript source code and view the result in realtime. It applies QML, JavaScript and asset changes instantly on every connected device, immediately after saving. On top of that, Hot Reload will keep the application state untouched, so you will continue exactly where you are in your application. This is a huge addition to the former QML Live Reload, as it saves you the time to navigate through your application again and again after each iteration.

Here is a short summary of the most important benefits that technology offers to you.

Incremental UI building

You can build your user interface incrementally while navigating it at the same time, and iterate on any subpage without navigating to it repeatedly. You can add navigation items, pages and subpages and modify their content and immediately see the outcome.

Work on a single screen until it is pixel perfect, without ever leaving it. Felgo Live will fully preserve the application state and apply the change directly in your running app. No need to navigate back to the subpage or popup that you are currently working on after each change.

Define interaction seamlessly

Hot Reload also allows you to add any form of interaction to the running QML application. You can add property bindings, signal handlers and regular JavaScript functions at any point to the QML tree. The new definitions are effective immediately.

Deploy and Test in Seconds

Even though QML does not have to be compiled, it only exists alongside the Qt C++ core. So traditionally, testing a change in your QML based application still requires you to compile, package and deploy the application. This is no longer the case with Felgo Live.

Any change in your QML, JavaScript or assets is immediately transferred and applied to your running application within 1 second. Traditional deployment time highly varies depending on your target platform, but can be up to several minutes!

Concurrent Testing on All Your Devices

Testing on multiple devices usually means that you have to deploy to all of them one-by-one. This time sums up quickly, and often leads to only one device being used during daily development. As a result, many issues might pop up when testing on another device at a later point.

With Felgo Live you can connect as many devices as you want, and every single one is updated simultaneously. This allows you to test any change on different platforms and devices at the same time, still within 1 second!

As a side note, it also allows you to test on your iOS device from Windows and Linux, without the need of a Mac!

Catch errors early

Hot Reloading encourages you to save and test your source code frequently. After you change even a single line of code, you can hit save and immediately see the result. This way you can catch errors way earlier and speed up your overall development process.

How does QML Hot Reload with Felgo Live Work?

Felgo Live basically consists of 2 parts, the Live Server and the Live Client.

Live Server

The Live Server observes your source code and detects code changes. It is also used to connect all your applications to use them with Hot Reloading.

On every detected code change, it sends the change to all connected clients using your local network. Nothing is leaving your local network by the way, no need to worry if you have any safety concerns.

For more information about the Live Server, you can visit the documentation.

Live Client

The Live Client is used to run your application on your target device. Felgo provides default Live Clients for Desktop (part of the installation) as well as for iOS and Android, which can be downloaded from the app stores.

Those clients are basically Qt applications that already include the most common Qt modules, and can to connect to the Live Server to run your application with Hot Reload.

You can find more information about the default Live Client in the documentation.

Besides the default Live Clients, you can also turn your own application into a Live Client. The next section tells you when and why this is needed.

Use QML Hot Reloading with custom C++ or Native Code

Many Qt projects still make use of C++ in addition to QML. Those parts will require a compilation step to be available in the application. With the Felgo Live Module, you can add QML Hot Reload capabilities to your own application. This way, you will only have to run the build process for changes in your C++, and can use Hot Reloading for QML, JS and assets.

You can learn how to integrate the Felgo Live Module, with 3 lines of code, in the documentation.

Spoiler: Add an additional config in your *.pro file

CONFIG += felgo-live

And inlude and intialize the FelgoLiveClient instead of your main QML file in your main.cpp

// Add this include
#include <FelgoLiveClient>

int main(int argc, char *argv[]) {
  
  // ...
  
  // Comment those lines to not load Main.qml ...
  // felgo.setMainQmlFileName(QStringLiteral("qml/Main.qml"));
  // engine.load(QUrl(felgo.mainQmlFileName()));

  // ... and instead load the FelgoLiveClient
  FelgoLiveClient liveClient(&engine);
}

Then build and run the application from Qt Creator and connect it to your Live Server.

There us also a small demo project that shows how to intergrate the Felgo Live Module in a plain Qt project on GitHub.

If you use CMake instead of qmake, contact us to help you get this set up as well.

How to Use Felgo Live with Qt and Felgo Projects

You can find a quick guide on how to use Felgo Live in the documentation.

QML Hot Reload also works for Qt projects that do not use any Felgo components. If you wonder how Felgo can further improve your application and development process, see the benefits of Felgo for Qt developers.

What is QML Hot Reload and How does it Work? Is it Magic?

Here are some details about how QML Live Reload and QML Hot Reload work. It is not magic, but it gets close!

For basic understanding, here is a great definition of live and hot reload, and their difference, found on stackoverflow:

Live reloading reloads or refreshes the entire app when a file changes. For example, if you were four links deep into your navigation and saved a change, live reloading would restart the app and load the app back to the initial route.

Hot reloading only refreshes the files that were changed without losing the state of the app. For example, if you were four links deep into your navigation and saved a change to some styling, the state would not change, but the new styles would appear on the page without having to navigate back to the page you are on because you would still be on the same page.

QML Live Reload

This is a very simplified visualization of a Qt application:

The C++ layer is the Qt core and does all the heavy lifting. It also contains a QML engine, that is able to execute QML code at runtime. This is the perfect precondition for a live reloading system.

The Felgo Live Module is a C++ module that can be added to such an application. It allows the application to connect to a Live Server to receive the new source code and to reload the whole QML part. This would look something like that:

The Live Server observes your project source code and assets. After any change, the new files are sent to the Live Client and picked up by the Live Client Module inside. Then the Live Client Module makes sure that the existing QML layer is destroyed correctly, the changed files are in place and a new updated QML layer is built up by the QML engine.

This Live Client Module is what you can also add to your own application, as described further above, to turn it into a Live Client.

QML Hot Reload

The general layout is pretty much the same as with QML Live Reload, but there is a major difference when it comes to the details. Take another look at the last image above.

It is not telling the whole truth, as the QML layer is also very much part of the C++ layer. When the QML code is executed, everything is translated to a huge tree of C++ objects. The tree-like structure comes from the fact that QML items are using parent/child dependencies.

Compared to a live reload, a hot reload will not destroy the running QML layer.

The Felgo Live Module will calculate the type of operation involved in such a change (add, update, move, remove, etc…), identify all matching objects in the C++ object tree and modify them accordingly to the change, and add/remove new objects where needed.

As a result you can add and remove QML objects and set their properties in code while the app is running. You can also define new properties, signals and functions into existing QML objects. Basically all features of the QML language are supported by Hot Reload.

QML Hot Reload with Felgo Live is supported on every platform supported by Qt, including Desktop, iOS, Android and Embedded. Here is a short Video from our Hot Reload showcase on the Embedded World Conference:

Focus on Development – Stop Waiting for Build, Package and Deployment Steps

Now it is your turn! Check out QML Hot Reload with Felgo Live and boost your productivity.

Download Felgo or update your existing Felgo installation! QML Hot Reload is available with Felgo 3.4.0 and later.

 

Download Felgo

 

 

 

This could also be interesting:


Release 3.4.0: QML Hot Reload with Felgo Live

 


Continuous Integration and Delivery (CI/CD) for Qt and Felgo

The post QML Hot Reload with Felgo Live for Qt appeared first on Felgo.

Ideas to help working from home

When I came to KDAB to work, working at home was a bit of a culture shock for me – I’d previously only ever worked in an open-plan office and had sworn that home working was not for me – I’d never manage to get anything done! However, I’ve found that home working suits me quite well, and given the current situation I thought I’d write a little about it as some people might be experiencing home working for the first time.

The first concern I had when starting to work from home was the loneliness. This is particularly relevant now, however there are still ways to ensure that you don’t get completely isolated. One thing would be to have meetings via video call – and not to forget that you can also do this with friends in the evening! Having social contact is important, even if you can’t meet up face to face.

The other main concern I had was how to separate working time from non-working time – both the physical and mental aspects. As a physical space, I use my PC desk for gaming which is not ideal, but I make sure after I work I move to another room to differentiate ‘work’ and ‘play’. A better way would be to have two different spaces set up, however with limited space – I live in a flat – I make sure that I at least have a break in between the two uses. Mentally, at the end of each day I like to plan what I’ll do first in the morning, so that it’s part of my wind down for a working day – which allows me to start the next day without getting distracted. At the end of the week I upload my timesheet to say to myself ‘that’s it’ – a very definite point where I’m done for the week.

As most of my colleagues have been working from home for longer than me, I asked around for some other tips. Here’s a selection of what they suggested:

  • have a dedicated desk/space that you keep reasonably clean and free from private stuff
  • everybody says this, but I find it helps: get up at the usual time, shower, get dressed properly as if going to an office and then dress down at the end of your working day to show to yourself that you are now off work
  • using a ‘commute’ to simulate going to work, for example cycling or walking round the block
  • set a work schedule for yourself that you need to determine (mainly so it’s easier to keep personal/family life separate from work life – work can be a distraction from personal life if you don’t keep them separate)
  • plan your meals just like you would if you were to bring your lunchbox to an office, otherwise you’ll keep escaping to the kitchen for snacking
  • consider eating more frequently throughout the day (6 small meals), so you don’t get too tired – it’s easy to get tired when you are inside all day every day.
  • having a wide selection of teas/coffees/drinks is also a nice thing
  • unless you have small kids with whom this isn’t going to work, tell your family that you can’t be reached during work hours except in emergencies and stick to that
  • everything that forms a routine probably helps
  • vary the position you sit in – maybe even creating a homemade ‘standing desk’ by putting a laptop on a higher table
  • make sure you take breaks to stretch and to allow your eyes to refocus – programs used by my colleagues to help with this include https://userbase.kde.org/RSIBreak and http://www.workrave.org/
  • using the Pomodoro technique to split your work time into intervals of 25 minutes, then taking a break. More can be found here: https://en.wikipedia.org/wiki/Pomodoro_Technique
  • also taking breaks gives time to for the brain to work in the background: I solve many complex software design problems when drying up the dishes
  • getting fresh air, even if it means just standing in an open window for ten minutes at a time
  • exercise indoors, maybe even replace your desk chair with an exercise ball – proper exercise helps you feel happy; it is a known treatment for mild depression
  • Some tried and tested suggestions from colleagues:

How has working at home worked for you? Are you facing any particular challenges? Have you any tips that you would like to share?

The post Ideas to help working from home appeared first on KDAB.

Qt on RaspberryPi

Qt on RaspberryPi is really easy, but can be rather time consuming to build an image to run on raspberry pi with Qt 5. You can either do it up yourself manually grabbing the sources, tool chains, etc. You could also buy the Qt for device creation package which comes with great support, bells, whistles and commercial licensing, or build it yourself and use open source GPL licensing. To get started using the open sourced parts, you clone one git repo:

  • meta-boot2qt 
git clone git://code.qt.io/yocto/meta-boot2qt.git

 You then need to decide which device to target. I have a fancy new raspberry pi 4 hooked up to a touch screen, so I will choose that.

To get a list of the Boot2Qt targets run the command:

  meta-boot2qt/b2qt-init-build-env list-devices

To initialize the build environment for a raspberry pi:

 meta-boot2qt/b2qt-init-build-env init --device raspberrypi4

This will clone needed repo's.

You will then need to set up the environment specifically for your device by setting MACHINE
and then source the setup-environment.sh script:

 export MACHINE=raspberrypi4 
 source ./setup-environment.sh

Now, if you just want an image to run:

 bitbake b2qt-embedded-qt5-image

Sit back, enjoy a cuppa and a pizza on this fine day... Don't let the computer sleep, or you will kick yourself in a few hours when you check on the progress. My final image to be dd'd onto the sd card was found in

   tmp/deploy/images/raspberrypi4

This is what you will be presented with when you boot your device:

To build the sdk/sysroot the command would be:

 bitbake meta-toolchain-b2qt-embedded-qt5-sdk 

You can build other targets including qemu, which will give you an image that runs in the qemu emulator.

You can then also set up target kits in Qt Creator to target the raspberry pi, set up the device kit so you can run and debug on the device. More fun for all that time on your hands right now!

I write about creating device OS images using Qt's Boot To Qt and Bitbake for the Raspeberry Pi in my book, Hands-On Mobile and Embedded Development with Qt 5


Debugging and Profiling Qt 3D applications

Qt 3D, being a retained mode high level graphic API abstraction, tries to hide most of the details involved in rendering the data provided by applications. It makes a lot of decisions and operations in the background in order to get pixels on the screen. But, because Qt 3D also has very rich API, developers can have a lot of control on the rendering by manipulating the scene graph and, more importantly, the frame graph. It is however sometimes difficult to understand how various operations affect performance.

In this article, we look at some of the tools, both old and new, that can be used to investigate what Qt 3D is doing in the back end and get some insight into what is going on during the frame.

 

Built in Profiling

The first step in handling performance issues is, of course, measuring where time is spent. This can be as simple as measuring how long it took to render a given frame. But to make sense of these numbers, it helps to have a notion of how complex the scene is.

In order to provide measurable information, Qt 3D introduces a visual overlay that will render details of the scene, constantly updated in real time.

 

The overlay shows some real time data:

  • Time to render last frame and FPS (frames per second), averaged and plotted over last few seconds. As Qt 3D is by default locking to VSync, this should not exceed 60fps on most configurations.
  • Number of Jobs: these are the tasks that Qt 3D executes on every frame. The number of jobs may vary depending on changes in the scene graph, whether animations are active, etc.
  • Number of Render Views: this matches loosely to render pass, see below discussion on the frame graph.
  • Number of Commands: this is total number of draw calls (and compute calls) in the frame.
  • Number of Vertices and Primitives (triangles, lines and points combined).
  • Number of Entities, Geometries and Textures in the scene graph. For the last two, the overlay will also show the number of geometries and textures that are effectively in use in the frame.

As seen in the screen shots above, the scene graph contains two entities, each with one geometry. This will produce two draw calls when both objects are in frame. But as the sphere rotates out of the screen, you can see the effect of the view frustum culling job which is making sure the sphere doesn’t get rendered, leaving a single draw call for the torus.

This overlay can be enabled by setting the showDebugOverlay property of the QForwardRenderer to true.

 

Understanding Rendering Steps

To make sense of the numbers above, it helps to understand the details of the scene graph and frame graph.

In the simple case, as in the screen shots, an entity will have a geometry (and material, maybe a transform). But many entities may share the same geometry (a good thing if appropriate!). Also, entities may not have any geometry but just be used for grouping and positioning purposes.

So keeping an eye on the number of entities and geometries, and seeing how that effects the number of commands (or draw calls), is valuable. If you find one geometry drawn one thousand times in a thousand separate entities, if may be a good indication that you should refactor your scene to use instanced rendering.

In order to provide more details, the overlay has a number of buttons that can be used to dump the current state of the rendering data.

For a deeper understanding of this, you might consider our full Qt 3D Training course.

Scene Graph

Dumping the scene graph will print data to the console, like this:

Qt3DCore::Quick::Quick3DEntity{1} [ Qt3DRender::QRenderSettings{2}, Qt3DInput::QInputSettings{12} ]
  Qt3DRender::QCamera{13} [ Qt3DRender::QCameraLens{14}, Qt3DCore::QTransform{15} ]
  Qt3DExtras::QOrbitCameraController{16} [ Qt3DLogic::QFrameAction{47}, Qt3DInput::QLogicalDevice{46} ]
  Qt3DCore::Quick::Quick3DEntity{75} [ Qt3DExtras::QTorusMesh{65}, Qt3DExtras::QPhongMaterial{48},
                                       Qt3DCore::QTransform{74} ]
  Qt3DCore::Quick::Quick3DEntity{86} [ Qt3DExtras::QSphereMesh{76}, Qt3DExtras::QPhongMaterial{48}, 
                                       Qt3DCore::QTransform_QML_0{85} ]

This prints the hierarchy of entities and for each of them lists all the components. The id (in curly brackets) can be used to identify shared components.

Frame Graph

Similar data can be dumped to the console to show the active frame graph:

Qt3DExtras::QForwardRenderer
  Qt3DRender::QRenderSurfaceSelector
    Qt3DRender::QViewport
      Qt3DRender::QCameraSelector
        Qt3DRender::QClearBuffers
          Qt3DRender::QFrustumCulling
            Qt3DRender::QDebugOverlay

This is the default forward renderer frame graph that comes with Qt 3D Extras.

As you can see, one of the nodes in that graph is of type QDebugOverlay. If you build your own frame graph, you can use an instance of that node to control which surface the overlay will be rendered onto. Only one branch of the frame graph may contain a debug node. If the node is enabled, then the overlay will be rendered for that branch.

The frame graph above is one of the simplest you can build. They may get more complicated as you build effects into your rendering. Here’s an example of a Kuesa frame graph:

Kuesa::PostFXListExtension
  Qt3DRender::QViewport
    Qt3DRender::QClearBuffers
      Qt3DRender::QNoDraw
    Qt3DRender::QFrameGraphNode (KuesaMainScene)
      Qt3DRender::QLayerFilter
        Qt3DRender::QRenderTargetSelector
          Qt3DRender::QClearBuffers
            Qt3DRender::QNoDraw
          Qt3DRender::QCameraSelector
            Qt3DRender::QFrustumCulling
              Qt3DRender::QTechniqueFilter
                Kuesa::OpaqueRenderStage (KuesaOpaqueRenderStage)
                  Qt3DRender::QRenderStateSet
                    Qt3DRender::QSortPolicy
            Qt3DRender::QTechniqueFilter
              Kuesa::OpaqueRenderStage (KuesaOpaqueRenderStage)
                Qt3DRender::QRenderStateSet
                  Qt3DRender::QSortPolicy
            Qt3DRender::QFrustumCulling
              Qt3DRender::QTechniqueFilter
                Kuesa::TransparentRenderStage (KuesaTransparentRenderStage)
                  Qt3DRender::QRenderStateSet
                    Qt3DRender::QSortPolicy
            Qt3DRender::QTechniqueFilter
              Kuesa::TransparentRenderStage (KuesaTransparentRenderStage)
                Qt3DRender::QRenderStateSet
                  Qt3DRender::QSortPolicy
          Qt3DRender::QBlitFramebuffer
            Qt3DRender::QNoDraw
    Qt3DRender::QFrameGraphNode (KuesaPostProcessingEffects)
      Qt3DRender::QDebugOverlay
        Qt3DRender::QRenderStateSet (ToneMappingAndGammaCorrectionEffect)
          Qt3DRender::QLayerFilter
            Qt3DRender::QRenderPassFilter

If you are not familiar with the frame graph, it is important to understand that each path (from root to leaf) will represent a render pass. So the simple forward renderer will represent a simple render pass, but the Kuesa frame graph above contains eight passes!

It is therefore often easier to look at the frame graph in term of those paths. This can also be dumped to the console:

[ Kuesa::PostFXListExtension, Qt3DRender::QViewport, Qt3DRender::QClearBuffers, Qt3DRender::QNoDraw ]
[ Kuesa::PostFXListExtension, Qt3DRender::QViewport, Qt3DRender::QFrameGraphNode (KuesaMainScene),
  Qt3DRender::QLayerFilter, Qt3DRender::QRenderTargetSelector, Qt3DRender::QClearBuffers, Qt3DRender::QNoDraw ]
[ Kuesa::PostFXListExtension, Qt3DRender::QViewport, Qt3DRender::QFrameGraphNode (KuesaMainScene), 
  Qt3DRender::QLayerFilter, Qt3DRender::QRenderTargetSelector, Qt3DRender::QCameraSelector, Qt3DRender::QFrustumCulling, 
  Qt3DRender::QTechniqueFilter, Kuesa::OpaqueRenderStage (KuesaOpaqueRenderStage), Qt3DRender::QRenderStateSet, 
  Qt3DRender::QSortPolicy ]
[ Kuesa::PostFXListExtension, Qt3DRender::QViewport, Qt3DRender::QFrameGraphNode (KuesaMainScene), 
  Qt3DRender::QLayerFilter, Qt3DRender::QRenderTargetSelector, Qt3DRender::QCameraSelector, Qt3DRender::QTechniqueFilter, 
  Kuesa::OpaqueRenderStage (KuesaOpaqueRenderStage), Qt3DRender::QRenderStateSet, Qt3DRender::QSortPolicy ]
[ Kuesa::PostFXListExtension, Qt3DRender::QViewport, Qt3DRender::QFrameGraphNode (KuesaMainScene),
  Qt3DRender::QLayerFilter, Qt3DRender::QRenderTargetSelector, Qt3DRender::QCameraSelector, Qt3DRender::QFrustumCulling,
  Qt3DRender::QTechniqueFilter, Kuesa::TransparentRenderStage (KuesaTransparentRenderStage), Qt3DRender::QRenderStateSet,
  Qt3DRender::QSortPolicy ]
[ Kuesa::PostFXListExtension, Qt3DRender::QViewport, Qt3DRender::QFrameGraphNode (KuesaMainScene),
  Qt3DRender::QLayerFilter, Qt3DRender::QRenderTargetSelector, Qt3DRender::QCameraSelector, Qt3DRender::QTechniqueFilter,
  Kuesa::TransparentRenderStage (KuesaTransparentRenderStage), Qt3DRender::QRenderStateSet, Qt3DRender::QSortPolicy ]
[ Kuesa::PostFXListExtension, Qt3DRender::QViewport, Qt3DRender::QFrameGraphNode (KuesaMainScene),
  Qt3DRender::QLayerFilter, Qt3DRender::QRenderTargetSelector, Qt3DRender::QBlitFramebuffer, Qt3DRender::QNoDraw ]

Hopefully this is a good way of finding out issues you may have when building your custom frame graph.

Draw Commands

On every pass of the frame graph, Qt 3D will traverse the scene graph, find entities that need to be rendered, and for each of them, issue a draw call. The number of objects drawn in each pass may vary, depending on whether the entities and all of their components are enabled or not, or whether entities get filtered out by using QLayers (different passes may draw different portions of the scene graph).

The new profiling overlay also gives you access to the actual draw calls.

So in this simple example, you can see that two draw calls are made, both for indexed triangles. You can also see some details about the render target, such as the viewport, the surface size, etc.

That information can also be dumped to the console which makes it easier to search in a text editor.

 

Built in Job Tracing

The data above provides a useful real time view on what is actually being processed to render a particular frame. However, it doesn’t provide much feedback as to how long certain operations take and how that changes during the runtime of the application.

In order to track such information, you need to enable tracing.

Tracing tracks, for each frame, what jobs are executed by Qt 3D’s backend. Jobs involve updating global transformations and the bounding volume hierarchy, finding objects in the view frustum, layer filtering, picking, input handling, animating, etc. Some jobs run every frame, some only run when internal state needs updating.

If your application is slow, it may be because jobs are taking a lot of time to complete. But how do you find out which jobs take up all the time?

Qt 3D has had tracing built in since a few years already, but it was hard to get to. You needed to do your own build of Qt 3D and enable tracing when running qmake. From thereon, every single run of an application linked against that build of Qt 3D would generate a trace file.

In 5.15, tracing is always available. It can be enabled in two ways:

  • By setting the QT3D_TRACE_ENABLED environment variable before the application starts (or at least before the aspect engine is created). This means the tracing will happen for the entire run of the application.
  • If you’re interested in tracing for a specific part of your application’s life time, you can enable the overlay and toggle tracing on and off using the check for Jobs. In this case, a new trace file will be generated every time the tracing is enabled.

For every tracing session, Qt 3D will generate one file in the current working directory. So how do you inspect the content of that file?

KDAB provides a visualisation tool but it is not currently shipped with Qt 3D. You can get the source and build it from GitHub here. Because jobs change from one version of Qt 3D to the next, you need to take care to configure which version was used to generate the trace files. Using that tool, you can open the trace files. It will render a time line of all the jobs that were executed for every frame.

In the example above, you can see roughly two frames worth of data, with jobs executed on a thread pool. You can see the longer running jobs, in this case:

  • RenderViewBuilder jobs, which create all the render views, one for each branch in the frame graph. You can see some of them take much longer that others.
  • FrameSubmissionPart1 and FrameSubmissionPart2 which contain the actual draw calls.

Of course, you need to spend some time understanding what Qt 3D is doing internally to make sense of that data. As with most performance monitoring tools, it’s worth spending the time experimenting with this and seeing what gets affected by changes you make to your scene graph or frame graph.

Job Dependencies

Another important source of information when analysing performance of jobs is looking at the dependencies. This is mostly useful for developers of Qt 3D aspects.

Using the profiling overlay, you can now dump the dependency graph in GraphViz dot format.

Other Tools

Static capabilities

Qt 3D 5.15 introduces QRenderCapabilities which can be used to make runtime decisions based on the actual capabilities of the hardware the application is running on. The class supports a number of properties which report information such as the graphics API in use, the card vendor, the supported versions of OpenGL and GLSL. It also has information related to the maximum number of samples for MSAA, maximum texture size, if UBOs and SSBOs are supported and what their maximum size is, etc.

Third Party Tools

Of course, using more generic performance tools is also a good idea.

perf can be used for general tracing, giving you insight where time is spent, both for Qt 3D and for the rest of your application. Use it in combination with KDAB’s very own hotspot to get powerful visualisation of the critical paths in the code.

Using the flame graph, as show above (captured on an embedded board), you can usually spot the two main sections of Qt 3D work, the job processing and the actual rendering.

Other useful tools are the OpenGL trace capture applications, either the generic ones such as apitrace and renderdoc, or the ones provided your hardware manufacturer, such as nVidia or AMD.

 

Conclusion

We hope this article will help you get more performance out of your Qt 3D applications. The tools, old and new, should be very valuable to help find bottlenecks and see the impact of changes you make to your scene graph or frame graph. Furthermore, improvements regarding performance are in the works for Qt 6, so watch this space!

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Debugging and Profiling Qt 3D applications appeared first on KDAB.

QtWebAssembly updates Emscripten Requirement

In the just released Qt 5.15-beta2 version, Qt for WebAssembly will require an Emscripten update from 1.38.27 to 1.39.8. Require because there are a few incompatible changes we needed in Qt.

The update includes several improvements, including faster linking times, as Emscripten no longer has to transpile to javascript before it outputs wasm. It can build directly to wasm thanks to upstream wasm support in clang.

Users will notice app build times are greatly improved on all platforms, since Emscripten no longer has a two pass linker procedure.

To update Emscripten, I usually do this from the commandline:

cd ~/emsdk
git pull
./emsdk update-tags
./emsdk install 1.39.8
./emsdk activate --embedded 1.39.8

and finally

source ~/emsdk/emsdk_env.sh


Of course, you will need to rebuild Qt, all other modules and apps.

You can read more about Qt for WebAssembly and Embedded Qt development in the book Hands-On Mobile and Embedded Development with Qt 5

MooseAche

MooseAche is the latest revolution in web browsing! Go back and forward! Save files! Get help! (you'll need it). Any similarity to other browsers is entirely coincidental.

QtWebEngineWidgets is not included in the main PyQt5 repository. If you see errors when running this relating to this module, you can install it using pip install PyQtWebEngine

The full source code for MooseAche is available in the 15 minute apps repository. You can download/clone to get a working copy, then install requirements using:

pip3 install -r requirements.txt

You can then run MooseAche with:

python3 browser.py

Read on for a walkthrough of how the code works.

The browser widget

The core of our browser is the QWebView which we import from PyQt5. QtWebEngineWidgets. This provides a complete browser window, which handles the rendering of the downloaded pages.

Below is the bare-minimum of code required to use web browser widget in PyQt.

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtWebEngineWidgets import *

import sys

class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow,self).__init__(*args, **kwargs)

        self.browser = QWebEngineView()
        self.browser.setUrl(QUrl("http://www.google.com"))

        self.setCentralWidget(self.browser)

        self.show()

app = QApplication(sys.argv)
window = MainWindow()

app.exec_()

If you click around a bit you'll discover that the browser behaves as expected — links work correctly, and you can interact with the pages. However, you'll also notice things you take for granted are missing — like an URL bar, controls or any sort of interface whatsoever. This makes it a little tricky to use.

To convert this bare-bones browser into something usable we can add some controls, as a series of QActions on a QToolbar. We add these definitions to the __init__ block of the QMainWindow.

navtb = QToolBar("Navigation")
navtb.setIconSize( QSize(16,16) )
self.addToolBar(navtb)

back_btn = QAction( QIcon(os.path.join('icons','arrow-180.png')), "Back", self)
back_btn.setStatusTip("Back to previous page")
back_btn.triggered.connect( self.browser.back )
navtb.addAction(back_btn)

The QWebEngineView includes slots for forward, back and reload navigation, which we can connect to directly to our action's .triggered signals.

next_btn = QAction( QIcon(os.path.join('icons','arrow-000.png')), "Forward", self)
next_btn.setStatusTip("Forward to next page")
next_btn.triggered.connect( self.browser.forward )
navtb.addAction(next_btn)

reload_btn = QAction( QIcon(os.path.join('icons','arrow-circle-315.png')), "Reload", self)
reload_btn.setStatusTip("Reload page")
reload_btn.triggered.connect( self.browser.reload )
navtb.addAction(reload_btn)

home_btn = QAction( QIcon(os.path.join('icons','home.png')), "Home", self)
home_btn.setStatusTip("Go home")
home_btn.triggered.connect( self.navigate_home )
navtb.addAction(home_btn)

While forward, back and reload can use built-in slots to perform their actions, the navigate home button requires a custom slot function. The slot function is defined on our QMainWindow class, and simply sets the URL of the browser to the Google homepage. Note that the URL must be passed as a QUrl object.

def navigate_home(self):
    self.browser.setUrl( QUrl("http://www.google.com") )

Any decent web browser also needs an URL bar, and some way to stop the navigation.

self.httpsicon = QLabel() # Yes, really!
self.httpsicon.setPixmap( QPixmap( os.path.join('icons','lock-nossl.png') ) )
navtb.addWidget(self.httpsicon)

self.urlbar = QLineEdit()
self.urlbar.returnPressed.connect( self.navigate_to_url )
navtb.addWidget(self.urlbar)

stop_btn = QAction( QIcon(os.path.join('icons','cross-circle.png')), "Stop", self)
stop_btn.setStatusTip("Stop loading current page")
stop_btn.triggered.connect( self.browser.stop )
navtb.addAction(stop_btn)

As before the 'stop' functionality is available as a slot on the QWebEngineView itself, and we can simply connect the .triggered signal from the stop button to the existing slot. However, other features of the URL bar we must handle independently.

First we add a QLabel to hold our SSL or non-SSL icon to indicate whether the page is secure. Next, we add the URL bar which is simply a QLineEdit. To trigger the loading of the URL in the bar when entered (return key pressed) we connect to the .returnPressed signal on the widget to drive a custom slot function to trigger navigation to the specified URL.

def navigate_to_url(self): # Does not receive the Url
    q = QUrl( self.urlbar.text() )
    if q.scheme() == "":
        q.setScheme("http")

    self.browser.setUrl(q)

We also want the URL bar to update in response to page changes. To do this we can use the .urlChanged and .loadFinished signals from the QWebEngineView. We set up the connections from the signals in the __init__ block as follows:

self.browser.urlChanged.connect(self.update_urlbar)
self.browser.loadFinished.connect(self.update_title)

Then we define the target slot functions which for these signals. The first, to update the URL bar accepts a QUrl object and determines whether this is a http or https URL, using this to set the SSL icon.

This is a terrible way to test if a connection is 'secure'. To be correct we should perform a certificate validation.

The QUrl is converted to a string and the URL bar is updated with the value. Note that we also set the cursor position back to the beginning of the line to prevent the QLineEdit widget scrolling to the end.

def update_urlbar(self, q):

    if q.scheme() == 'https':
        # Secure padlock icon
        self.httpsicon.setPixmap( QPixmap( os.path.join('icons','lock-ssl.png') ) )

    else:
        # Insecure padlock icon
        self.httpsicon.setPixmap( QPixmap( os.path.join('icons','lock-nossl.png') ) )

    self.urlbar.setText( q.toString() )
    self.urlbar.setCursorPosition(0)

It's also a nice touch to update the title of the application window with the title of the current page. We can get this via browser.page().title() which returns the contents of the <title></title> tag in the currently loaded web page.

def update_title(self):
    title = self.browser.page().title()
    self.setWindowTitle("%s - Mozarella Ashbadger" % title)

File operations

A File menu was added with self.menuBar().addMenu("&File") assigning the F key as a Alt-shortcut. Once we have the menu object, we can can add QAction objects to it to create the entries. We create two basic entries here for opening and saving HTML files (from a local disk). These both require custom slot method.

file_menu = self.menuBar().addMenu("&File")

open_file_action = QAction( QIcon( os.path.join('icons','disk--arrow.png') ), "Open file...", self)
open_file_action.setStatusTip("Open from file")
open_file_action.triggered.connect( self.open_file )
file_menu.addAction(open_file_action)

save_file_action = QAction( QIcon( os.path.join('icons','disk--pencil.png') ), "Save Page As...", self)
save_file_action.setStatusTip("Save current page to file")
save_file_action.triggered.connect( self.save_file )
file_menu.addAction(save_file_action)
````        

The slot method for opening a file uses the built-in
`QFileDialog.getOpenFileName()` method to create a
file-open dialog and get a name. We restrict the names by
default to files matching `\*.htm` or `*.html`.

We read the file into a variable `html` using standard
Python functions, then use `.setHtml()` to load the HTML
into the browser.

```python
def open_file(self):
    filename, _ = QFileDialog.getOpenFileName(self, "Open file", "", 
                    "Hypertext Markup Language (*.htm *.html);;"
                    "All files (*.*)")

    if filename:
        with open(filename, 'r') as f:
            html = f.read()

        self.browser.setHtml( html )
        self.urlbar.setText( filename )

Similarly to save the HTML from the current page, we use the built-in QFileDialog.getSaveFileName() to get a filename. However, this time we get the HTML from self.browser.page().toHtml() and write it to the selected filename. Again we use standard Python functions for the file handler.

def save_file(self):
    filename, _ = QFileDialog.getSaveFileName(self, "Save Page As", "",
                    "Hypertext Markup Language (*.htm *html);;"
                    "All files (*.*)")

    if filename:
        html = self.browser.page().toHtml()
        with open(filename, 'w') as f:
            f.write(html)

Help

Finally, to complete the standard interface we can add a Help menu. We add two custom slot methods to handle the display of the dialog, and to load the 'browser page' with more information.

help_menu = self.menuBar().addMenu("&Help")

about_action = QAction( QIcon( os.path.join('icons','question.png') ), "About Mozarella Ashbadger", self)
about_action.setStatusTip("Find out more about Mozarella Ashbadger") # Hungry!
about_action.triggered.connect( self.about )
help_menu.addAction(about_action)

navigate_mozarella_action = QAction( QIcon( os.path.join('icons','lifebuoy.png') ), "Mozarella Ashbadger Homepage", self)
navigate_mozarella_action.setStatusTip("Go to Mozarella Ashbadger Homepage")
navigate_mozarella_action.triggered.connect( self.navigate_mozarella )
help_menu.addAction(navigate_mozarella_action)

The first method navigate_mozzarella opens up a page with more information on the browser, the second creates and executes a custom QDialog class AboutDialog.

def navigate_mozarella(self):
    self.browser.setUrl( QUrl("https://martinfitzpatrick.name/create-simple-gui-applications") )

def about(self):
    dlg = AboutDialog()
    dlg.exec_()

The definition for the about dialog is given below. The structure follows that seen earlier in the book, with a QDialogButtonBox and associated signals to handle user input, and a series of QLabels to display the application information and a logo.

The only trick here is adding all the elements to the layout, then iterate over them to set the alignment to the center in a single loop. This saves duplication for the individual sections.

class AboutDialog(QDialog):

    def __init__(self, *args, **kwargs):
        super(AboutDialog, self).__init__(*args, **kwargs)

        QBtn = QDialogButtonBox.Ok  # No cancel
        self.buttonBox = QDialogButtonBox(QBtn)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        layout = QVBoxLayout()

        title = QLabel("Mozarella Ashbadger")
        font = title.font()
        font.setPointSize(20)
        title.setFont(font)

        layout.addWidget(title)

        logo = QLabel()
        logo.setPixmap( QPixmap( os.path.join('icons','ma-icon-128.png') ) )
        layout.addWidget(logo)

        layout.addWidget( QLabel("Version 23.35.211.233232") )
        layout.addWidget( QLabel("Copyright 2015 Mozarella Inc.") )

        for i in range(0, layout.count() ):
            layout.itemAt(i).setAlignment( Qt.AlignHCenter )

        layout.addWidget(self.buttonBox)

        self.setLayout(layout)

Further ideas

If you're looking for a browser which supports tabbed browsing, check out Mozzarella Ashbadger. This is based on this same code, but with the addition of tabs, and using signal-redirection to route behaviours based on the active tabs.

GammaRay 2.11.1 Release

We have released version 2.11.1 of our Qt application introspection tool GammaRay. The changes mainly focus on establishing full compatibility with Qt 5.14 as well as bugfixes and performance improvements, but there’s also a few new features.

Areas most affected by changes in Qt 5.14 are the inspection of Qt Quick software rendering, deployment on Android and signal monitoring. We also fixed a major performance issue that can be caused by interference between the newly added event monitor in GammaRay 2.11 and the Qt Quick remote view feature, as well as the in-app widget overlay causing layouting issues when applied to a QSplitter. The Qt 3D geometry inspector now has a OpenGL ES2 fallback implementation in case your host machine doesn’t support OpenGL 3, and the event monitor can now also visualize event propagation in Qt Quick’s input handling.

You can find the full changelog here.

GammaRay is available as part of the Qt Automotive Suite including QtCreator integration and professional support, in the Qt Market Place, or GPL-licensed on Github.

 

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post GammaRay 2.11.1 Release appeared first on KDAB.

Release 3.4.0: QML Hot Reload with Felgo Live

Felgo 3.4.0 introduces QML Hot Reload to cut the waiting times to build, deploy and iterate on Qt and Felgo projects.

Hot Reload with Felgo Live allows you to change your QML & JavaScript source code and view the result in realtime. It applies QML, JavaScript and asset changes instantly on every connected device, immediately after saving. This reduces the long waiting times for build and deployment steps to only a couple of seconds.

Hot Reload applies changes in your source code without losing the state of your application. If you are currently working on a sub-page, you will not have to navigate back to it after every change, you will stay exactly where you are in your app.

You can also test your projects on mobile, without installing native mobile SDKs, only by installing the Felgo Live App on your device. Hot Reload even works on embedded devices!

 

Hot Reload can be used with Felgo and also pure Qt projects, on any platform. Hot Reload is available for any Felgo user, including the free Personal license.

Try Hot Reload Now

Hot Reloading for QML, JavaScript and Assets

Hot Reload keeps your application running while it applies code changes. This means your app or game keeps its exact state when reloading. This helps speed up development even more than with live reloading.

Incremental UI building

You can build your user interface incrementally while navigating it at the same time, and iterate on any sub-page without navigating to it repeatedly. You can add navigation items, pages and sub pages and modify their content and immediately see the outcome on multiple platforms.

Work on a single screen until it is pixel perfect, without ever leaving it. Felgo Live will fully preserve the application state and apply the change directly in your running app. No need to navigate back to the sub-page or popup that you are currently working on after each change.

Define interaction seamlessly

Hot Reload also allows you to add any form of interaction to the running QML application. You can add property bindings, signal handlers and regular JavaScript functions at any point to the QML tree. The new definitions are effective immediately.

Support for Custom C++ and Native Code

If your application contains any custom C++ code, native code, additional libraries or any Qt module that is not already pre-configured with the default Live Client app, you can make use of the Live Client Module.

This C++ module can be added to your own project with 3 lines of code. This will enhance your own application with Hot Reload features. Just build it normally for any desired platform and connect it to your Live Server, just like the default Live Client.

You can find more information about the Live Client Module in the documentation.

How to Use Hot Reloading with Felgo Live

You can find a detailed guide in the documentation. Here is a short summary of the steps.

Note: If you already use Live Reloading, just update Felgo and your Live Client apps and you are ready to go.

After installing/updating Felgo, if you open a project in Qt Creator, the Felgo Live Server will automatically start. You can also manually start the Live Server using the “Live Run” button, the green triangle with “LIVE” in Qt Creator.

Depending on your autostart setting of the Desktop Live Client, you will also see the Felgo Live Client application start. You can also start the Live Client for Desktop with the start button in your Live Server.

The Live Server is watching for changes in your source code, and pushes the changes to the Live Client, which will display your application.

You can also connect your mobile device to the Live Server. Just download the Felgo Live Scripting app for iOS or Android directly on your device, click connect, and accept the request in your Live Server. Every code change will then be displayed on any connected device at the same time.

The new Hot Reload feature can also be disabled, to only use Live Reloading instead. This can be helpful if you experience any issue with your specific setup, or Hot Reloading is not desired for any reason. A full reload can also be triggered at any time.

Please refer to the documentation for more details.

How does Hot Reload with Felgo Live Work?

You will be able to get a closer look at how Hot Reloading works soon, in another blog post. For those who can’t wait, there are also some insights in the documentation.

Firebase Authentication using your Google/Gmail Account

With Felgo 3.4.0 you can now also let your users log in to Firebase with their Google/Gmail account, with the new loginUserWithGoogle() method.

More Features, Improvements and Fixes

Felgo 3.4.0 includes many more features, for example:

  • OneSignal::notificationReceived() now provides information about the push notification’s action buttons.
  • NativeUtils::contacts now contains more information about contacts. The new information includes postal addresses, email addresses, company name and phone number types.
  • The Facebook Plugin now supports the native SDK v5.13.0 on iOS.
  • Examples now use the latest project format of Felgo, which allows you to provide more configuration values, like the license key, from your *.pro file.
  • NativeUtils::displayImagePicker() no longer leaves behind a temporary file on iOS.
  • Fixes the Deprecated API Usage warning for UIWebView when uploading an app to the iOS App Store.
  • Fixes an Android SSL version issue while building, which previously required you to apply a hotfix.
  • Fixes a crash with the OneSignal requestTags method.
  • Fixes an issue with Android 10 API blacklisting.

For all relevant changes, features and fixes of recent Felgo updates, please check out the changelog.

How to Update Felgo

Test out these new features by following these steps:

  • Open the Felgo SDK Maintenance Tool in your Felgo SDK directory.
  • Choose “Update components” and finish the update process to get this release as described in the Felgo Update Guide.

Update Felgo

If you haven’t installed Felgo yet, you can do so now with the latest installer from here. Now you can explore all of the new features included in this release!

For a full list of improvements and fixes to Felgo in this update, please check out the change log!

 

 

 

More Posts Like This


Release 3.3.0: Update to Qt 5.13.2 and Qt Creator 4.10.2, Jira Tima App Demo

Release-3-2-0-Qt-5123-EcmaScript7-QtCreator-482
Release 3.2.0: Update to Qt 5.12.3 with ECMAScript 7, Subscriptions, Image Picker and Qt Creator 4.8.2


Release 3.1.0: New Felgo Plugins Version, Unified App Configuration and FlickablePage

The post Release 3.4.0: QML Hot Reload with Felgo Live appeared first on Felgo.

Using Visual Studio Code for Qt Applications – Part One

A few weeks ago, we published an article with an overview of Visual Studio Code through the eyes of a Qt developer.

In this short blog series, I will show you how to get up to speed with a Qt project using Visual Studio Code more in detail. Before digging into the Qt parts, I’d like to go through an overview of the bits and pieces that are needed to configure any C++ project.

Setup a workspace

With Visual Studio Code you can start hacking on your code pretty much right away, just by opening the folder where your code resides. Sometimes if you’re just skimming through a codebase and you just want to be able to look for specific strings on the whole project folder that is all you need.

You can also manage multiple folders at the same time on a single Visual Studio Code window, search for strings on all files on all folders, and if you set up your workspace properly, also cross navigate between files in different folders with the help of a C++ code model.

Screenshot of a visual studio code windows on a workspace with two folders

A Visual Studio Code workspace is just a bundle of opened folders

In any case, you can add a folder to your workspace by selecting the “File” menu and then “Add folder to workspace…”. Removing folders from a workspace is done by right clicking on a folder and then selecting “Remove Folder from Workspace”.

Doing anything more than just reading and searching through your code will require you to save and possibly adjust your workspace. Let’s start from saving your workspace. To do so, click on the “File” menu and select “Save Workspace As…”.

Once you have saved your workspace file, you can start editing it. That can be done through Visual Studio Code itself since it is basically a JSON file listing all folders belonging to the project and workspace level (that is, global) settings. If you have multiple folders, you may want to assign a name to each one as it might be helpful later on. To do so, edit the workspace file, and add a “name” attribute to the object relative to your folder, alongside the “path” attribute.

Short video showing how to update folder names on Visual Studio Code workspaces

Get the right extensions

Putting the C++ developer hat on, other than just being able to search through your source code, you may also want some code model to be available, so that you can easily detect for instance wrong includes, typos in variables names and the like.

Visual Studio Code is language agnostic by nature, but lets you do this on C/C++ code bases by means of a C++ extension, which you can find in the marketplace under the unsurprising name “C/C++” (full extension identifier: ms-vscode.cpptools).

If you plan to use CMake in your projects, another handy extension is “CMake Tools” (ms-vscode.cmake-tools).

You can install them both as shown below, after opening the command list by pressing “Ctrl+Shift+P”.

Configuration files

Now that the workspace is configured we can finally go on and set up build configurations, run configurations and C++ specific settings. We will see these operations in detail below, but before doing that it’s worth spending a few extra words on some common concepts.

If you don’t have any configuration file yet, be it a run, build, or C++ settings file, Visual Studio Code will create them for you as soon as you try to update your configuration. By default, it will do so by creating a .vscode subfolder under your first workspace folder, and placing all your configuration files there. You can also choose to have one .vscode subfolder for each one of your workspace folders and add configuration files in each of them. This will let you adjust settings on a per-folder basis.

In all configuration files, you can use ${workspaceFolder} to refer to the current source code folder. It is important to keep in mind that ${workspaceFolder} will always refer to the workspace folder where the configuration files reside. If you want to access other workspace folders, you can do it by explicitly referring to their name in the workspace configuration file, so if the folder is named “folder1” in the workspace file, you can access it in the configuration file using ${workspaceFolder:folder1}.

Add and run build configurations

The first step to add a new build configuration is to open the command line (Ctrl+Shift+P) and select “Tasks: Run Task”. You will be prompted to create a “tasks.json” file if you don’t have one already. For a simple build task, just select “Others” for the task type. This will create an example “shell” build configuration which lets you run a command from your shell with a number of arguments.

From now on you can start setting up your build configurations as in the example below.

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Build target1",
      "type": "shell"
      "command": "make /f ${workspaceFolder:folder1}/Makefile target1"
      "options": {
        "cwd": "${workspace:folder1}"
      }
    }
    // ... add more tasks here
  ]
}

Once builds are configured Visual Studio code will allow you to:

  • mark a run configuration as default (Ctrl+Shift+P -> “Tasks: Configure Default Build Task”)
  • run a specific build configuration (Ctrl+Shift+P -> “Tasks: Run Task”, then select from the list of available build configurations)
  • run the default build configuration (Ctrl+Shift+P -> “Tasks: Run Build Task” or just Ctrl+Shift+B)
How to use MSVC in a build configuration

When launching a build configuration on Windows, you will not have access to the MSVC compiler and all its associated environment variables by default. So if you try to run for instance nmake to build your project your build will fail.

This is usually solved by calling vcvarsall.bat (or its moral equivalent for later Visual Studio versions) before launching a build. We can’t do that straight away here because a shell run configuration command will be run through Windows’ PowerShell console and not through the classic command prompt, and vcvarsall.bat won’t run on PowerShell.

One way to fix this is to install the pscx module on your PowerShell. You can do it by running a PowerShell with administrator rights and typing:

Install-Module pscx

Once the module is installed you can run any batch file and retain the resulting environment by running Invoke-BatchFile. You can now use nmake (or any other MSVC binary) in a build configuration as in the example below:

{
  "label": "Build target1",
  "type": "shell"
  "command": "Invoke-BatchFile 'PATH_TO_YOUR_VCVARS' ; nmake /f ${workspaceFolder:folder1}/Makefile target1"
  "options": {
     "cwd": "${workspace:folder1}"
  }
}

Add and run launch configurations

The next step once your app is built is to add launch configuration(s) so you can debug (or just run) your executable(s).

First, let’s get Visual Studio Code to create a launch configuration file for you by opening the command line (Ctrl+Shift+P), selecting “Debug: Open launch.json”, and then “C++ (Windows)”. This will create a new launch.json configuration file. From there, it’s enough to update the “program” and “cwd” parameters on the autogenerated file to get a working configuration.

Once you’re done your launch configuration should look like this:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "target1",
      "type": "cppvsdbg",
      "request": "launch",
      "program": "${workspaceFolder:folder1}/build/target1",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder:folder1}/build",
      "environment": []
    }
    // ... add more targets here
  ]
}

Similarly to what happens with the build configuration file, you can add a new launch configurations by adding a new JSON object under the “configurations” list.

Once this is done, you can see a list of run configurations on the debug tab, which you can access by clicking on the small bug on the left side of the window or by pressing “Ctrl+Shift+D” on windows.

Workspace level configurations

All the build and run configurations we saw until now can also be set at a workspace level. This could be useful, for instance, if you want to access the same folder from multiple workspaces and different build configurations depending on the workspace.

The syntax is the same as for the folder level configuration files, you just have to put all the settings in your workspace file as in the following example:

{
  "folders": [ .... ],
  "settings": [ .... ],
  "tasks": [
    { ... first build conf ... },
    { ... second build conf ... }
  ],
  "launch": [
    { ... first run conf ... },
    { ... second run conf ... }
  ]
}

Set up the code model

With the steps described up to now, it will be possible to navigate across all files within the project which is currently opened inside the editor. It will also be possible to use code completion (IntelliSense) for all the types inside said project.

But what if your project is using third party libraries (say, Qt) and you want to be able to navigate to library headers and have code completion for library types (say, QObject, or QWidget)?

This can be configured thanks to the C/C++ extension installed before. To get it to work, we need to edit the configuration file for this extension by going to the command prompt (Ctrl+Shift+P) and selecting “C/C++: Edit configurations (JSON)”.

This is what the default configuration will look like on Windows:

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "windowsSdkVersion": "10.0.17763.0",
            "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.22.27905/bin/Hostx64/x64/cl.exe",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "msvc-x64"
        }
    ],
    "version": 4
}

Here it is possible to tweak with the C and C++ standard versions (cStandard and cppStandard), but the most important fields if you want to include third party libraries to the code model properly are includePath and defines.

includePath is a JSON list and will tell the code model builder where to look for header files, so, for instance, if you are using Qt in your project, you will need to add something like “C:/Qt/5.12.7/msvc2017_64/include/**”. Note the trailing **, that tells the code model to look for headers in all the subfolders.

defines is a list that will tell the code model builder which preprocessor defines to use for building the code model. They should ideally reflect the ones that will be used at build time, as the C/C++ plugin can’t infer them from build tasks.

This concludes the first round of notes about using Visual Studio Code in your C++/Qt projects. It includes all the fundamental pieces and should be enough to get started using Visual Studio Code effectively. In the next posts I will go more into details on how to add Qt, qmake and cmake to the scene.

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

 

The post Using Visual Studio Code for Qt Applications – Part One appeared first on KDAB.

A message regarding operations during the COVID-19 pandemic

We at the Qt company share the concern about the current coronavirus (COVID-19) pandemic that is currently affecting us all. I would like to take a moment just to reassure you that, despite the current global challenges, The Qt Company has taken proactive actions to ensure that all services will continue at our usual high-standards (without disruption) and that the well-being of our staff, customers and partners is being protected to the best of our abilities.

In regard to our employees and their families in particular, we have restricted travel and encouraged working from home. Qt employees are used to working remotely and with people all around the world. Despite the extraordinary circumstances, we are keeping operations running, and you can contact us through the regular channels and continue to rely on us to support you and your business. We hope the Qt ecosystem stays lively through this challenging period, keeping in touch through online channels.

Although we have had to cancel or postpone many face-to-face meetings and events, we are available through online meetings and have put additional effort into online resources and events.

How to Handle Safe Area Insets, Notch & Display Cutout for iPhone X, iPad X and Android P – 2020

More and more mobile devices feature a notch (or display cutout, as it is called on Android). To handle this little monster, mobile app developers now face many new challenges.

The trend is spreading fast and many manufacturers already announced new 2018 models with edge-to-edge screens. For example with Android P devices like Essential Phone, OnePlus 6, Oppo R15 Pro, Vivo X21, LG G7, Huawei P20 or Asus Zenfone 5. Similar to the iPhone X, Apple’s new iPad Pro model, the iPad X, will also include a notch and feature Face ID.

 

How hard can it be to support the notch – maybe one or two days to optimize existing apps for it?

 

That’s what we initially thought. As it turned out, it was a lot harder than expected. We ran into many bumps along the road of porting 20+ apps & games to properly support it.

As a native iOS and Android developer, you will experience similar issues yourself when you start to develop for devices with edge-to-edge screens. For iOS, Apple even requires you to support iOS 11 and the notch: All new apps & app updates submitted after July 2018 get rejected otherwise.

So we put up our sleeves and prepared this guide to show you how to support the notch in your apps. Thus the sooner you start following this guide the better you are prepared for the Apple change coming in July and for upcoming Android P changes.

The tips provided in this guide apply for both iOS and Android and are useful for cross-platform developers as well. Along the way, we also modified all the components in Felgo, a cross-platform framework for app & game development. It now supports the notch out-of-the-box, so you don’t need to go through this „notch hell“ yourself. 🙂

Looking for Qt Training, Consulting or Software Development?

Here we go! We hope you enjoy the „Ultimate Guide to Survive the Notch“:

User Interface Challenges of Devices with Edge-to-Edge Displays

Many manufacturers already announced new models with edge-to-edge screens, which became even more popular after the release of the iPhone X:

Devices with Edge-to-Edge Screens and a Notch or Display Cutout

Such screens allow to get the most out of the available space the device offers. In addition to the rounded edges, there is a main pain point for mobile app developers: the notch.

iPhone X with Edge-To-Edge Display vs. iPhone 8

Instead of a clear rectangular frame, app developers now face arbitrary shaped screens. Also, hardware buttons at the front no longer exist. They got replaced by on-screen buttons and gestures provided by the OS. The following sections describe how to create adaptive layouts to handle those challenges for both iOS & Android. While this post uses examples for iPhone X, the same concepts and suggested solutions also apply for other devices & platforms with similar screens, like upcoming Android P devices.

Use Felgo’s iOS and Android app development services, in case you need help with that.

Bigger Screen Size and Safe Area of iPhone X

For the iPhone X, the new screen holds two major factors to account for in your mobile app:

  • The screen is bigger in general, so there’s more space your app can use.
  • Your app content should not cover areas with a notch or native on-screen buttons. Otherwise, the elements you place at these parts of the screen are not accessible.

To support different device models and screens, most apps use a responsive layout. This means that the pages use the full height and width to show as much content as possible. This is a good thing. But if the notch and reserved areas are not taken into consideration, some parts of your app are covered or inaccessible.

Full-screen app content gets covered by the notch or on-screen gestures.

In the example screenshots shown above for the iPhone X, the notch covers the top navigation bar in portrait mode and your page content, the list item text, in landscape mode. For both orientations, the area for the home swipe gesture overlays your app at the bottom. Also note that the new screen comes with rounded corners.

To solve this problem, your app needs to consider the safe area of the screen. It is the part of your app, which won’t be covered by the notch or on-screen gestures. The required top and bottom screen insets determine the safe area in portrait mode:

Top and bottom insets determine the safe area in portrait mode.

For example, the navigation bar requires more padding at the top to be within the safe area. In landscape mode it looks a bit different. We then require margins to the left and right (for the rounded corners and the notch), as well as a small inset at the bottom (for the home swipe gesture):

Insets to the left, right and bottom determine the safe area in landscape mode.

How Do Existing Apps Look on iPhone X?

If you are worrying that your published app is already affected by the notch, you can relax. Only apps configured to target iPhone X will run full-screen. Your existing iOS apps will come with black borders as shown on the right in this image, to not overlay areas with a notch or screen gestures:

iOS App with and without iPhone X Support

The disadvantages are that the borders do not look good and the app does not match the style of other iPhone X apps – your user’s will realize this and your app will get a worse rating. The black border fallback is simply a backwards compatibility feature by Apple to not break anything. However, it also means some work for us app developers to support the new screen.

How to Create iPhone X Apps with Xcode

Enable iPhone X Support for Your App

Unless your app enables support for iPhone X, it will show with black borders by default. This also means, that your existing apps won’t be affected by the notch. However, if you want to fully support iPhone X and let your app fill the whole screen, you need to add an additional launch image for the iPhone X resolution in Xcode:

Add new launch images to support iPhone X.

Add one image with 2436 x 1125 pixels for landscape mode, and one with 1125 x 2436 pixels if you want to support portrait.

Position Your Content to the Safe Area Layout Guide

Many iOS apps use a navigation bar at the top and a tab bar at the bottom. With iOS 7, Apple decided to add the topLayoutGuide and bottomLayoutGuide properties, which match the insets for these bars in the view. Developers can thus align their content to match these insets.

For iPhone X, it is not enough to only take care of the top and bottom margins. We also have insets to the left and right of the screen, e.g. when in landscape mode. So Apple introduced the new safeAreaLayoutGuide property with iOS 11. The top and bottom layout guides are now deprecated.

Use the safe area layout guide to align your content with the iPhone X safe area.

To make sure your content isn’t covered by the notch, position it to the safe area layout guide. Similar to the previous top and bottom layout guides, this can be done with constraints.

But this simple solution is still far from perfect. Especially in landscape mode, constraining your content area can leave some ugly margins. To avoid this, you can instead add custom insets to your content only where necessary.

The new safeAreaInsets property gives access to the exact pixel inset for the safe area. You can thus tweak the layout to look exactly as you want. For example, you can design the cells of your list items to account for the safe area with a bigger indent. The view content can then cover the whole screen.

Use safe area insets to optimize your layout for landscape mode.

How to Migrate Existing Native iOS Apps to work with Safe Area Insets

To make updating your apps a bit easier, you have the option to activate the Use Safe Area Layout Guides setting for each of your Storyboards in Xcode.

"Use Safe Area Layout Guide" setting for Xcode storyboards.

The Storyboard then replaces the top and bottom layout guides with a safe area and updates the constraints. This is a quick first measure to get your app ready for iPhone X.

But as mentioned above, you will still need to check all your views to provide the best possible user experience. For example, to:

  • Let the background of a sub-view use the full screen while keeping the content safe.
  • Decide how to handle the insets when flicking a UIScrollView.
  • Set up your UITableView or UICollectionView to correctly layout for iPhone X.

Full-screen content vs. optimized layout for iPhone X.

Also, you might not be happy with the result of the default Use Safe Area Layout Guides setting in case your app hides the system status bar:

iPhone X Notch Issue with Hidden StatusBar

Due to a bug within the latest iOS 11 SDK, the navigation bar does not account for the notch in this case. Except for some workarounds, there is no simple solution for this issue at the moment of writing this guide. At least when relying on native iOS development with Xcode.

Android P Developer Preview: Display Cutouts

Many Android phone manufacturers already announced their upcoming device models with edge-to-edge displays and rounded corners. For example:

Upcoming Android Devices with Display Cutout

Google also already released the developer preview for Android P. It comes with the ability to handle these so-called display cutouts. In the iOS world, display cutout is equivalent to notch.

How to Test Apps with Display Cutout in Android P

The Android P Developer Preview allows simulation of display cutout. Android P is available with the SDK Manager of Android Studio. It is sufficient to install the Android P SDK and System Image to test on a virtual Android P device:

The Android P Developer Preview is available with the SDK Manager.

After installation is complete, you can start an emulator running Android P. The developer settings on Android P offer four different display cutout options to choose from:

Android P Developer Settings - Display Cutout Simulation

After selecting this option, the Android device will show with a bigger status bar that also includes a display cutout:

Android P Developer Preview with Simulated Display Cutout

The layoutInDisplayCutoutMode attribute controls how the window is laid out if there is a display cutout. By default your Android P app never extends into cutout areas – with a single exception. As visible on the image above, your app can safely cover the full screen for cutouts that do not exceed the status bar area.

Note: The window will lose this ability to extend into the cutout area when FLAG_FULLSCREEN or SYSTEM_UI_FLAG_FULLSCREEN is set.

To let your app always take advantage of the full screen, you can set the value LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. You are then responsible to keep your app content within the safe area of the screen. For example, when the device is in landscape mode or if the cutout exceeds the status bar in portrait.

Custom Layouts with Safe Area Insets in Android P

Like iOS 11, Android P includes features to determine the safe area of the screen and work with the given insets. The new DisplayCutout class lets you find out the location and shape of the non-functional areas where content shouldn’t be displayed.

To determine the existence and placement of the cutouts areas, use the getDisplayCutout() method. You can then access the following fields for the DisplayCutout:

Overall it means quite some work to let your app layout adapt to these new displays. Especially for developers that target both iOS and Android.

Save Time and Effort with Felgo Engine for Mobile Apps

Create iOS and Android Apps that Support The Notches and Display Cutouts

Felgo Engine focuses on making mobile app development easy. And it also supports the iPhone X notch and Android P devices with display cutouts out-of-the-box. You can write your app once, and build for iOS, Android or even Desktop with a single button press from 1 IDE. The source code is 100% shared across all platforms.

Felgo Support for Android P and Display Cutouts

Felgo builds upon C++ & Qt and utilizes QML & JavaScript. QML is a fast and easy-to-use declarative UI language. With only a few lines of code, it is possible to create native iOS and Android apps that look native on every device:

import Felgo 3.0
import QtQuick 2.0

App {
  // adds tab navigation (iOS) or drawer menu (Android) 
  Navigation {

    // first tab
    NavigationItem {
      icon: IconType.home
      title: "Main"

      // main page
      NavigationStack {
        Page {
          title: "Main"

          Rectangle {
            anchors.fill: parent // Rectangle fills whole Page
            color: "lightgreen"

            AppText {
              anchors.centerIn: parent // AppText is centered on Page
              text: "Safe Area"
            }
          }
        }
      }
    }

    // second tab
    NavigationItem {
      icon: IconType.gears
      title: "Settings"

      // settings page
      NavigationStack {
        Page { title: "Settings" }
      }
    }

  }
}

 

This is how the above example app looks like on an iPhone X:

Felgo Support for iPhone X and the Notch

The used components like Navigation and NavigationStack are prepared to work with safe area insets: They automatically include extra margins for the tab and navigation bar if required.

In contrast to the native iOS SDK it is also possible to hide the status bar without any issues. You can do this by setting a single property in your code:

import Felgo 3.0
import QtQuick 2.0

App {
  onInitTheme: {
    Theme.colors.statusBarStyle = Theme.colors.statusBarStyleHidden
  }

  // main page
  NavigationStack {
    Page {
      title: "Main"

      AppButton {
        anchors.horizontalCenter: parent.horizontalCenter
        text: "Toggle Status Bar"
        onClicked: {
          if(Theme.statusBarStyle !== Theme.colors.statusBarStyleHidden)  
            Theme.colors.statusBarStyle = Theme.colors.statusBarStyleHidden
          else
            Theme.colors.statusBarStyle = Theme.colors.statusBarStyleBlack
        }
      }
    }
  }
}

No status bar issue for iPhone X apps created with Felgo.

The top navigation bar in Felgo always supports the notch automatically, even with a hidden status bar.

Like the Use Safe Area Layout Guide setting for Xcode Storyboards, the content of your pages does not overlap reserved areas of the screen. But Felgo requires no extra setting to achieve this. The page content aligns with the safe area out-of-the box. For devices without a notch, the app does not show any extra margins or insets:

Felgo Components are prepared to support the safe area out-of-the-box.

Note: Configure iPhone X launch images for your iOS app to get full-screen support on iPhone X if you have an existing Felgo app. For new apps, this is set up automatically.

Optimize your User Interface with Adaptive Layouts

For most use cases, the default settings are fine to let your app look good on devices with and without display cutouts. If you want more control over how to display your content, you can disable the useSafeArea setting of each Page. You then have two options to work with the safe area:

  1. Configure only certain content items within the Page to align with the safe area.
  2. Retrieve the exact safe area inset of the screen and layout items as required.

The following example deactivates the useSafeArea setting and shows both options:

import Felgo 3.0
import QtQuick 2.0

App {

  Page {
    useSafeArea: false // the page content can use all available space

    // fill whole page/screen with blue color (background)
    Rectangle {
      anchors.fill: parent
      color: "lightblue"
    }

    // Option 1: fill only safe area with green color (content)
    Rectangle {
      anchors.fill: parent.safeArea
      color: "lightgreen"
    }

    // Option 2: adaptive background to cover top inset area (or status bar area on devices without insets)
    Rectangle {
      width: parent.width
      height: nativeUtils.safeAreaInsets.top > 0 ? nativeUtils.safeAreaInsets.top : nativeUtils.statusBarHeight()
      color: "yellow"
    }
  }

}

 

The page content can now cover the full screen by default. You can use the safeArea property of the Page to align items with the safe area of the screen. In the above example, we use this to fill the safe area with a green rectangle. This is where you can place your content items.

The nativeUtils.safeAreaInsets hold the exact safe area insets of the screen in pixels. Devices without a notch do not have any insets and thus return 0. For iPhone X, the yellow rectangle will cover the top inset, which includes the status bar. To also support older devices, you fill the status bar if no inset is returned by nativeUtils.safeAreaInsets.top.

The available safeAreaInsets properties are:

  • nativeUtils.safeAreaInsets.top
  • nativeUtils.safeAreaInsets.right
  • nativeUtils.safeAreaInsets.bottom
  • nativeUtils.safeAreaInsets.left

Running this app on iOS or Android produces the following result:

Create adaptive layouts to perfectly support the notch or display cutouts in your apps.

Developing adaptive user interfaces this way is very convenient. The following example shows how you could use nativeUtils.safeAreaInsets.left to add more indent for the cells of a list.

import Felgo 3.0
import QtQuick 2.0

App {

  NavigationStack {
    ListPage {
      title: "List Page"
      useSafeArea: false // the page fills all available space
      model: 50 // quick way to populate the list with 50 items

      // UI for cells of the list
      delegate: SimpleRow {
        text: "Item #"+index

        // set indent of the cells
        // matches the safe area inset or minimum 16 dp (if no inset required, e.g. in portrait mode or on older devices)
        style.indent: Math.max(nativeUtils.safeAreaInsets.left, dp(16))
      }
    }
  }
  
}

With such simple additions, you can make sure that your app looks pixel-perfect on screens with and without safe area insets.

Adaptive Layout Example: Full-width list cells in landscape mode.

You don’t need to add such tweaks for apps that offer the default UI with a navigation bar and tab bar. The Felgo page and navigation components look good on all devices and adapt their style automatically.

Support for Display Cutout on Android P Devices

Felgo Engine is a cross-platform development tool that supports both Android and iOS. You can take the QML code of your iOS app and directly build for Android, or vice-versa. All components change their look and behavior then. They match the native style and user experience of the given platform:

Felgo Supports both iOS 11 and Android P.

The above image shows the Android and iOS style for the same example app. The Android style is already prepared to support edge-to-edge screens. No extra work is required, to make your app work cross-platform for iOS & Android with display cutouts, safe area and a notch!

Simulate Safe Area Insets while Developing on Desktop

It takes quite some time to always build and deploy to your phone or the simulator. With Felgo you can run and test your app directly on Desktop. It is even possible to simulate different devices and resolutions to see how your app will look like. You can change the resolution at runtime, without having to restart your app. This is a huge time-saver for UI development & testing! Native development for Android or iOS requires deployment to another real or virtual device to test the UI.

Felgo Device Resolution Simulation on Desktop

Along with the support for a display notch, Felgo also comes with a new resolution simulator entry for iPhone X. And the best thing is: It even covers the safe area insets you get on a real device:

iPhone X Desktop Simulation with Safe Area Insets

Felgo Engine is thus a huge time-saver when developing for iOS and Android. The Felgo SDK is free to use, so make sure to check it out!

If you need help with your mobile app development, use Felgo’s consulting and app development services.

More Relevant App Development Resources

The Best App Development Tutorials & Free App Templates

All of these tutorials come with full source code of the mobile apps! You can copy the code to make your own apps for free!

App Development Video Tutorials

 

 

Thanks for reading & scrolling that far! 🙂

Do you have suggestions for posts or tutorials about app development?
Simply send us a message which tutorial you’d like to see here.

 

More Posts Like This

feature
How to Make Cross-Platform Mobile Apps with Qt – Felgo Apps

teaser-iphonex-support-and-runtime-screen-orientation-change-705px
Release 2.16.0: iPhone X Support and Runtime Screen Orientation Changes

How to Expose a Qt C++ Class with Signals and Slots to QML
How to Expose a Qt C++ Class with Signals and Slots to QML

The post How to Handle Safe Area Insets, Notch & Display Cutout for iPhone X, iPad X and Android P – 2020 appeared first on Felgo.

QML Hot Reload: Felgo presents hot new feature at Embedded World 2020!

This year’s Embedded World exhibition & conference has concluded. Felgo attended as Qt Technology Partner at the Qt booth.

Visitors were able to put their hands on one of our hottest new features: QML Hot Reload (pun intended!). Here’s a quick video of the demo right at the booth:



Short live demo of QML Hot Reload at the booth.

 

Hot Reload with Felgo Live allows you to change your QML & JavaScript source code and view the result in realtime. It applies QML, JavaScript and asset changes instantly on every connected device, on any platform, including embedded. This reduces the long waiting times for build and deployment steps to only a couple of seconds. 

Hot Reload applies changes in your source code without losing the state of your application. If you are currently working on a sub-page, you will not have to navigate back to it after every change, you will stay exactly where you are in your app.

Stay tuned for the upcoming official announcement of QML Hot Reload with Felgo Live, as part of the upcoming Felgo 3.4.0 update!

 

Get Started with Felgo for Embedded

 

The Felgo booth – thank you for stopping by!

 

The Coronavirus, that just started to spread in northern Italy the week before the show, had a significant impact on the event. Some major exhibitors were missing, and attendance was also significantly down compared to 2019.

Even though the show was smaller than the last few years, it was great to connect & network with our customers, partners and many new people! We’re looking forward to having more conversations in the coming weeks & months on how to support developers with the latest technologies around Felgo, Qt & embedded systems development.

Test the new features now in the Felgo SDK. Download for free today!

The post QML Hot Reload: Felgo presents hot new feature at Embedded World 2020! appeared first on Felgo.

Getting rid of “volatile” in (some of) Qt

The upcoming version of the C++ Standard (C++2a) is proposing to deprecate certain usages of the volatile keyword, by adopting the P1152 proposal (Deprecating volatile).

Despite the somewhat “flamboyant” title, the actual deprecated parts are very limited and indeed the paper limits the deprecation to somehow language/library corner cases and/or dangerous antipatterns.

For instance certain read-modify-write operations on a variable declared volatile are now deprecated, like:

volatile int i = 42;
++i;     // deprecated
i *= 2;  // also deprecated

In any case, I took the occasion for digging a bit into Qt’s own usages of volatile. I didn’t do a thorough search through the entirety of Qt because I’ve also tried to fix the mis-usages…

In this blog post I am going to share some of my discoveries.

volatile foo used in place of std::atomic<foo>

As usual, the problem here is that volatile in C++ has nothing to do with synchronization/atomicity. (Ok, that’s not entirely true on all systems, but it’s true enough.)

There are at least two big offenders I found this way.

1: QQmlIncubationController::incubateWhile(volatile bool *)

The incubateWhile call takes a pointer to volatile bool. The idea is that the pointed boolean gets periodically checked by the incubator controller; another thread can tell the controller to stop incubating by flipping that bool.

To be honest, I’m not 100% convinced by the soundness of this API. For instance, it could’ve accepted a function object to poll, moving the problem of the eventual synchronization from another thread to the user’s domain. When in doubt, making it someone else’s problem is usually a good choice.

But I don’t want to redesign the QML engine APIs here, so I’ve just attempted a fix by porting to std::atomic<bool> instead.

The fix will appear in Qt 5.15.

2: QObjectPrivate::threadData

QObjectPrivate::threadData is a raw pointer to QThreadData (i.e. QThreadData *), basically storing the thread affinity of a given QObject, by holding a pointer to that thread’s private data.

The problem is that that variable is read and written by multiple threads without synchronization. For instance it’s written from here:

void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData)
{
    ...
   
    // set new thread data
    targetData->ref();
    threadData->deref();
    threadData = targetData; // <-- the write
    
    ...
}

and potentially read from here:

void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{
    ...
    
    QThreadData * volatile * pdata = &receiver->d_func()->threadData; // <-- the read
    ...
}

These calls can happen from different threads, without synchronization — postEvent is documented to be thread-safe. Therefore, we have a data race, and data races are undefined behavior.

This ended up being super-tricky to fix (and I’m still not sure of it).

Sure, the idea is to make QObjectPrivate::threadData an atomic pointer to QThreadData, but then how to fix all the usage points?

The big struggle is that QObject is merely reentrant, and not thread safe, so most cases don’t require any synchronization (and can be turned into relaxed loads) because you’re not supposed to be modifying that variable by multiple threads without synchronization. Big exception: the cases that involve code paths that are documented to be thread-safe, like the postEvent code path above, which thus require acquire loads.

The current fix draft is sitting here.

The most interesting part is probably the old loop in postEvent(), trying to lock receiver‘s thread event queue:

    QThreadData * volatile * pdata = &receiver->d_func()->threadData;
    QThreadData *data = *pdata;
    if (!data) {
        // posting during destruction? just delete the event to prevent a leak
        delete event;
        return;
    }

    // lock the post event mutex
    data->postEventList.mutex.lock();

    // if object has moved to another thread, follow it
    while (data != *pdata) {
        data->postEventList.mutex.unlock();

        data = *pdata;
        if (!data) {
            // posting during destruction? just delete the event to prevent a leak
            delete event;
            return;
        }

        data->postEventList.mutex.lock();
    }

This loop used volatile once more to “cheat” synchronization: the code needs to get the threadData of an object and lock its event queue. Before that’s done, however, the affinity of the object could’ve been changed, so we need to unlock and try again. The idea is sound, but volatile does not help at all here as far as C++ is concerned; it seems to work because the compiler actually reloads the value of receiver‘s threadData, since its access happens through a volatile pointer.

As a side note: the same loop was completely missing from other places, like QCoreApplication::removePostedEvents, that also need to lock an object’s event queue (oops!). So I fixed that too, as a drive-by change…

volatile as a way to tell the compiler to… stop thinking

The QLibraryInfo class stores, amongst other things, the path to Qt’s own installed “parts” (plugins, translations, etc.). This path is hardcoded at build time; it’s one of the reasons why a Qt installation cannot be easily relocated.

In QLibraryInfo there’s a mysteriousconst char * volatile path” variable:

#ifndef QT_BUILD_QMAKE_BOOTSTRAP
    if (!fromConf) {
        const char * volatile path = 0;
        if (loc == PrefixPath) {
            path = getPrefix(
#ifdef QT_BUILD_QMAKE
                        group
#endif
                   );
        } else if (unsigned(loc) <= sizeof(qt_configure_str_offsets)/sizeof(qt_configure_str_offsets[0])) {
            path = qt_configure_strs + qt_configure_str_offsets[loc - 1];
#ifndef Q_OS_WIN // On Windows we use the registry
        } else if (loc == SettingsPath) {
            path = QT_CONFIGURE_SETTINGS_PATH;
#endif
# ifdef QT_BUILD_QMAKE
        } else if (loc == HostPrefixPath) {
            static const QByteArray hostPrefixPath = getHostPrefixFromHostBinDir().toLatin1();
            path = hostPrefixPath.constData();
# endif
        }

        if (path)
            ret = QString::fromLocal8Bit(path);
    }
#endif

What’s it for? It turned out to be a complete hack.

In order to achieve relocation of Qt libraries (for instance, to allow the binary Qt installers to install Qt in any path specified by the user), Qt can be built with a dummy installation path. The installer will then binary patch Qt, replacing this dummy path with the actual installation path.

What’s the hack, then? The hack is to prevent the compiler to aggressively inline the call to QString::fromLocal8Bit below, which involves a call to strlen(path).

With path set to a compile-time string literal, strlen(path) would also be fully evaluated at compile time, and that would make the binary patch not work — it would end up with path and its length not matching, and making fromLocal8Bit return broken data or crash horribly. This has actually happened and has been reported as QTBUG-45307.

How to stop the compiler from calling strlen at compile-time? There you have it, don’t use a “const char *“, use a “const char * volatile” (a volatile pointer to const char). I have no idea why it actually works!

Didn’t fix it, but left a comment for the future reader.

volatile for setjmp/longjmp protection

Now we go into the legitimate use cases for volatile. C (and thus C++) define the setjmp and longjmp library functions. They do non-local jumps: longjmp jumps to a setjmp done somewhere before in the call stack.

In C they’re used as a poor man’s exception handling mechanism — return from a deep call stack up directly to a caller, unwinding the stack in the process. Since it’s C, every object is trivially destructible, so there’s nothing special to do to perform the unwinding. In C++ performing a longjmp that would destroy non-trivially destructible objects yields undefined behavior.

volatile has an interesting interaction with setjmp/longjmp: it’s used to give well-defined semantics when using function local variables across the jump.

For instance, a snippet like this:

volatile int i = 0;
jmp_buf buf;

if (!setjmp(buf)) {
   // first time, enter here
   i = 42;
   longjmp(buf, 1);
}

// then go here after the longjmp
std::cout << i;

exhibits well-defined behavior (and prints 42) specifically because i is volatile. Without the volatile, i would have indeterminate value, and producing such an indeterminate value in this context is undefined behavior (I’m sensing a pattern here…). In other words: any local variable that is set after a setjmp and read after the longjmp must be declared volatile.

In layman’s terms: this volatile is telling the compiler something like “do not put i in a register and don’t optimize it out in any way; always keep it spilled on the stack, so it’s safe in case of a longjmp“.

Qt has a couple of places where there are setjmp/longjmp calls, namely its image handlers. PNG and JPEG use the respective C libraries (libpng and libjpeg), which seem to be designed with using setjmp/longjmp as a way to notify users of errors. That’s also where there are more usages of volatile.

PNG handler

In the case of the PNG image handler, a local variable was declared volatile, but that local was actually never accessed after the longjmp; so volatile wasn’t even needed in the first place. This has been fixed here.

JPEG handler

For the JPEG image handler, the situation was a bit more spicy. Sure thing, a local variable was again unnecessarily declared volatile (fix).

However the same code also was showing undefined behavior by not protecting some locals with volatile. For instance here, simplifying the code, we have this pattern:

JSAMPROW row_pointer[1];
row_pointer[0] = 0;
...
if (!setjmp(jerr.setjmp_buffer)) {
    ...
    row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
    ...
}
delete [] row_pointer[0];

The row_pointer local variable was not volatile; it was written after the setjmp (line 615) and then read again after the longjmp (line 716).

The fix in this case couldn’t be to simply mark it as volatile: the object in question is passed to libjpeg’s API, which simply want a pointer-to-object, and not a pointer-to-volatile-object (d’oh!). Marking an object with volatile, then const_cast‘ing volatileness away and accessing the object is an immediate undefined behavior, so don’t even think about doing it…

Also, libjpeg’s error handling requires the user to use setjmp/longjmp; therefore, the code had to keep the same structure (including the jumps). Basically, in libjpeg, one installs a custom error handling function; once libjpeg calls that handling function, it expects it not to return. So it must either exit the entire process, or longjmp out.

My fix was to make those variables non-local to the function calling setjmp, thus recovering well-defined behavior. You can read more about it in the fix’ commit message here.

longjmps, longjmps everywhere

Now the really interesting bit is that the very same code in the very same shape (and with the same very bug) is present everywhere.

For instance, it’s present in the equivalent GTK code in GDK that loads JPEG images here:

struct jpeg_decompress_struct cinfo;
...
if (sigsetjmp (jerr.setjmp_buffer, 1)) {
    ...
    jpeg_destroy_decompress (&cinfo);
    ...
}
...
jpeg_create_decompress (&cinfo);

Or in ImageMagick, here:

  struct jpeg_compress_struct
    jpeg_info;
    
  ...
  
  if (setjmp(error_manager.error_recovery) != 0)
    {
      jpeg_destroy_compress(&jpeg_info);
    }
    
  ...
  
  jpeg_create_compress(&jpeg_info);

It turns out that this kind of code comes all the way back from libjpeg version 6b’s own examples, dated 1998!

Those examples showcased the non-local return via setjmp/longjmp, and were affected by the same undefined behavior. You can still download them here (check out the sources for libjpeg 6b).

The historical libjpeg-turbo’s example also had the same problem. Comments are mine:

// 1. declare a non-volatile object
struct jpeg_decompress_struct cinfo;


if (setjmp(jerr.setjmp_buffer)) {
  // 3: and access it after the longjmp. 
  jpeg_destroy_decompress(&cinfo);
}

// 2. access it after the setjmp
jpeg_create_decompress(&cinfo);

I opened an issue asking for this to be fixed; the fix landed in this commit.

Conclusions

To conclude, let’s celebrate the longevity of this problem in all the codebases in the world. In perfect security-drama design: the most important part of an issue is its logo.

Therefore, here’s the official logo of the volatile handling in JPEG fiasco, of course made in 1998 style:

Thanks for reading!

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Getting rid of “volatile” in (some of) Qt appeared first on KDAB.

GitQlient: Multi-platform Git client written with Qt

I'm happy to announce the release of GitQlient 1.0.0.

For the version 1.0.0 I've implemented all the features that were part of GitQlientPlugin with some fixes and improvements. A way more that I initially thought. I've been using GitQlient for the last two weeks in my day-to-day work and I feel it's ready for this first version!

GitQlient: Multi-platform Git client written with Qt first appeared on My C++ & Qt blog - Cesc M..

KDSoap 1.9.0 released

KD SOAP is a tool for creating client applications for web services.

The release of 1.9.0 brings a fair number of improvements and fixes, as the following text describes.

General

  • C++11 is now required. Qt4 is still supported, but this is the last release with support for Qt4. rpath for Unix/Linux/macOS (#181) is now fixed.
  • cmake usage is improved by setting the install interface directories on the library targets (#196). You can just link to KDSoap::kdsoap and you’ll get the correct include paths now.
  • Conan has a new installing file (WIP – see conan folder).

Client-side

  • Support for selecting WS-Addressing namespace for send messages (#176) has been added
  • WS-Addressing spec compliance (#193) is fixed
  • Support for implementing SOAP-over-UDP clients (see KDSoapUdpClient) is fixed.

Server-side

WSDL parser / code generator changes, applying to both client and server side:

  • An override indicator to generated files has been added. This requires C++11 for users of generated files.
  • An option for loading PKCS12 certificates (#190) has been added.
  • All special handling of soap/encoding namespace is removed, which fixes the use of soapenc:string and soapenc:integer for instance (#179).
  • A compilation error due to missing QSharedPointer include in generated code (#170) is now fixed.

Examples

  • The holidays examples have been replaced with bank-lookup examples. Less fun, but the holidays web service no longer exists…

Download KDSoap

KDSoap on Github

KDABSoap Releases

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post KDSoap 1.9.0 released appeared first on KDAB.

How not to lose the alpha channel

Working on color imagery for QiTissue recently, I realized we were accidentally losing the alpha channel in multiple places. For efficiency reasons, we keep colors in memory using the QRgb type, and convert that to/from QString for serialization purposes via QColor as needed. Here’s what I discovered about why that doesn’t work, and some ways I fixed it.

Firstly, be aware there is no QRgba in the Qt API . There is only QRgb, for 8bit color channels. It can hold an alpha value too, despite the lack of a trailing a in the type name. Then there is QRgba64 which uses 16bit per color channel. For our purposes, 8bit per channel is sufficient. So where do we lose the alpha channel, when QRgb can store it in principle?

The first pitfall is QColor(QRgb), which calls QColor::fromRgb internally. Both of these functions silently ignore the alpha channel of the passed QRgb value and assume the color is fully opaque. To get around this, you have to use QColor::fromRgba instead.

QColor toColor(QRgb colorWithAlpha)
{
    // all bad: input alpha ignored, set to fully opaque
    return QColor(colorWithAlpha);
    return colorWithAlpha;
    return QColor::fromRgb(colorWithAlpha);
    // good:
    return QColor::fromRgba(colorWithAlpha);
}

Then you’ll find that QColor::name() also ignores the alpha channel. Here, you have to use QColor::name(QColor::HexArgb) instead.

QString toString(const QColor &colorWithAlpha)
{
    // bad: input alpha ignored, output is e.g. #112233
    return colorWithAlpha.name();
    // good: output is e.g. #00112233
    return colorWithAlpha.name(QColor::HexArgb);
}

Thankfully, the QColor constructors and QColor::setName function, which parse a string color name, won’t ignore the alpha channel when you pass an ‘#AARRGGBB’ string.

However, there is one more pitfall: When you have a QColorDialog with QColorDialog::ShowAlphaChannel, and listen to its currentColorChanged signal and set a color with an alpha channel on it, a stray change signal notification will be emitted with a fully opaque color. The reason is that, internally, the color dialog will first set the RGB color components, and then in a second step will set the alpha component. But both will trigger a change notification, where the first step holds a fully opaque color. This should be fixed upstream, but thankfully for now it is easy to workaround by ignoring the signal while setting a color from the outside.

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post How not to lose the alpha channel appeared first on KDAB.

Cutelyst 2.10.0 and SimpleMail v2 released!

Cutelyst the C++/Qt Web framework and SimpleMailQt just got new releases.

Cutelyst received many important bugfixes and if you are compiling it with View::Email it also requires SimpleMail 2, the latter got an Async API which is on production for a few months, allowing for a non-blocking send mail experience.

Check them out!

https://github.com/cutelyst/cutelyst/releases/tag/v2.10.0

https://github.com/cutelyst/simple-mail/releases/tag/v2.0.0

More foss stuff

It is busy days at the moment – but in a positive way.

First of all – a huge thanks to everyone who submitted to the Call for Papers for foss-north 2020. We have over 70 hours (!!!) of contents to squeeze into two tracks over two days. As always, it will be hard to pick the speakers to create the very best program.

Other foss-north activities includes starting to populate the community day activities, as well as getting a whole bunch on sponsors onboard. An extra big thanks to Luxoft and Red Hat Ansible for helping us by picking up the Gold Sponsorship packages. Ansible are even running their European Contributor Summit as a part of the foss-north Community Day together with events by KDE, Gnome, FreeBSD, Debian, and a hardware hacking workshop. I’m really looking forward to this – if you want to join in with your own project, workshop, hackaton, etc – just ping me!

The other big foss-north change for this year is that we are finally abandoning Eventbrite for a self-hosted system. Big thanks to Magnus Hagander helping us getting the pgeu-system up and running. At the moment, we offer login via Github and Google OAUTH. We’re looking into setting up a self-hosted OAUTH service as well, to let you log in locally, but that will not happen for the 2020 event due to time reasons.

Closer in time is the next local foss-gbg meetup. We are running an event around React together with our good friends at Edument. We already have 50+ registered attendees, so it will be fun!

In other news – I’ve also released Ordmonster – if anyone has kids who wants to get started reading. This is a complement to the Mattemonster app for basic maths launched earlier. Both are made with Godot, a tool that I enjoy more and more.

Qt World Summit 2019 talk videos are online

Did you miss the past Qt World Summit?

Were you there, but you couldn’t attend that talk or two that you really wanted to see because the conference was so, so packed with awesome content?

Fear no more! We are glad to announce that the talks at the past Qt World Summit 2019 in Berlin (or QtWS19, for the friends) have been video recorded and are now available online! You can now catch up with the latest news, improvements and best practices around Qt and its ecosystem, all from the comfort of your sofa office chair.

We have gathered all the talks given by KDAB engineers on this summary page, where you can find also more information about the contents of each talk and download the slides. For your convenience, we have also collected all of KDAB talks in a YouTube playlist:

The talks by other speakers are available for viewing in the Resource Center on www.qt.io.

Happy hacking!

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Qt World Summit 2019 talk videos are online appeared first on KDAB.