Skip to content

Replace QPainter with Blend2D in CMapIMG#1131

Draft
jmlzr wants to merge 2 commits into
Maproom:devfrom
jmlzr:QMS-1130
Draft

Replace QPainter with Blend2D in CMapIMG#1131
jmlzr wants to merge 2 commits into
Maproom:devfrom
jmlzr:QMS-1130

Conversation

@jmlzr

@jmlzr jmlzr commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What is the linked issue for this pull request:

QMS-#1130

What you have done:

Added Tracy as a profiler and instrumented the IMG rendering to look for where to focus my performance optimization efforts. That showed that Qt's rasterizer is the bottleneck that will dwarf any gains that could be made in the code. With the biggest bottlenecks being drawPolylines by and followed by drawPolygons.
So I decided to let Claude replace Qt's very slow rasterizer with Blend2D which is probably the fastest software rasterizer/vector graphics library in existence.

The new code seems to result in the same output but runs ~3 times faster!

Performance comparison

To make a comparison I recorded traces of me panning and zooming around the same area before and after the commit that switched to Blend2D and then used Tracy's compare feature.

drawPolylines saw a massive 5x improvement, dropping from 569ms mean to 117ms:

image

drawPolygons saw a also impressive 2.5x improvement, from 170ms to 67ms:

image

Looking at draw is deceiving as the results of that are diluted by early exists from redraw requests.

Render output

I took comparison screenshots before of the same view before and after, map used is a Freizeitkarte IMG.

Before:

qms-1130-kufstein-qt

After:

qms-1130-kufstein-blend2d

As you can see there is virtually no visible difference! The only thing I can notice on this view is the POIs shifting a little but they seem to shift by a similar amount with the previous renderer as well when panning minimally so I'm not sure if that is even a regression.

Next steps

Since this is a rather large change and I haven't checked if Claude did stupid things I made this just a draft for now. I do encourage people to try it out though!

I think now that the biggest bottleneck is gone I could also squeeze out probably at least another ~20% from optimizing the rest of the code.

Btw the massive amount of ISO C++ prohibits anonymous structs warnings comes from the fact that our CMakeLists.txt unfortunately sets global compile options with add_compile_options that then affects subprojects as well. The better thing would be to set them only for our own targets with target_compile_options. But we can fix that if we get close to merging this, for now I didn't want to bother with that.

Steps to perform a simple smoke test:

Open a IMG.

Tracy

If anyone wants to play with Tracy:

  1. Reconfigure QMS with -DTRACY_ENABLE=1 -DTRACY_ON_DEMAND=1
  2. Build Tracy, in the QMS build dir do:
cd _deps/tracy-src
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
cmake --build profiler/build --config Release -j$(nproc)
  1. Start Tracy from the same dir with ./profiler/build/tracy-profiler and connect to the running QMS instance.

Does the code comply to the coding rules and naming conventions Coding Guidelines:

  • yes

Is every user facing string in a tr() macro?

  • yes

Did you add the ticket number and title into the changelog? Keep the numeric order in each release block.

  • yes, I didn't forget to change changelog.txt

No as only a draft for now.

@kiozen

kiozen commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

First quick impression:

  • I am naturally a bit uneasy about another huge dependency. But let's see what the package maintainers say.
  • On my fairly weak private laptop I hardly notice any big difference. Maybe because reading the data takes the most of the time. Or belnd2d can't get much out of the Intel graphics adapter. Can't tell

@jmlzr

jmlzr commented Jun 24, 2026 via email

Copy link
Copy Markdown
Contributor Author

@wthaem

wthaem commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

My attempt to build the PR jmlzr:QMS-1130 with my default CMake parameters failed on Windows 11:

FAILED: [code=2] src/qmaptool/CMakeFiles/qmaptool.dir/canvas/CCanvas.cpp.obj
C:\PROGRA~1\MICROS~1\18\COMMUN~1\VC\Tools\MSVC\1451~1.362\bin\Hostx64\x64\cl.exe  /nologo /TP -DAPPLICATION_NAME=qmaptool -DHELPPATH=doc/HTML -DQT_CORE_LIB -DQT_GUI_LIB -DQT_HELP_LIB -DQT_NETWORK_LIB -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_WIDGETS_LIB -DUNICODE -DVER_MAJOR=1 -DVER_MINOR=20 -DVER_STEP=3 -DVER_TWEAK="" -DWIN32 -DWIN64 -D_CRT_SECURE_NO_WARNINGS -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_UNICODE -D_WIN64 -ID:\QtProjects\QMS\QMS4Qt6\build-ninja\src\qmaptool -ID:\QtProjects\QMS\QMS4Qt6\src\qmaptool -ID:\QtProjects\QMS\QMS4Qt6\build-ninja\src\qmaptool\qmaptool_autogen\include -ID:\QtProjects\QMS\QMS4Qt6\src\qmaptool\. -ID:\QtProjects\QMS\QMS4Qt6\src\qmaptool\..\common -external:ID:\QtProjects\QMS\QMS4Qt6\build-ninja -external:Id:\QtProjects\QMS\GISInternals\1944_260614\release-1944-x64\include -external:Id:\QtProjects\QMS\GISInternals\1944_260614\release-1944-x64\include\proj9 -external:IC:\Qt\6.11.0\msvc2022_64\include\QtWidgets -external:IC:\Qt\6.11.0\msvc2022_64\include -external:IC:\Qt\6.11.0\msvc2022_64\include\QtCore -external:IC:\Qt\6.11.0\msvc2022_64\mkspecs\win32-msvc -external:IC:\Qt\6.11.0\msvc2022_64\include\QtGui -external:IC:\Qt\6.11.0\msvc2022_64\include\QtNetwork -external:IC:\Qt\6.11.0\msvc2022_64\include\QtHelp -external:IC:\Qt\6.11.0\msvc2022_64\include\QtSql -external:W0 /wd4996 /wd4101 /wd4005 /wd4003 /EHsc /O2 /Ob2 /DNDEBUG /Zi /GL -std:c++20 -MD /MP -Zc:__cplusplus -permissive- -utf-8 /showIncludes /Fosrc\qmaptool\CMakeFiles\qmaptool.dir\canvas\CCanvas.cpp.obj /Fdsrc\qmaptool\CMakeFiles\qmaptool.dir\ /FS -c D:\QtProjects\QMS\QMS4Qt6\src\qmaptool\canvas\CCanvas.cpp
D:\QtProjects\QMS\QMS4Qt6\src\qmaptool\canvas\CCanvas.cpp(22): fatal error C1083: Datei (Include) kann nicht geöffnet werden: "tracy/Tracy.hpp": No such file or directory
[234/606] Building CXX object src\qmaptool\CMakeFiles\qmaptool.dir\overlay\gridtool\CGridSelArea.cpp.obj
ninja: build stopped: subcommand failed.

There are lots of new CMAKE variables. I used their default settings. More info is certainly needed to build successfully on Windows.

Must there any additional packages be downloaded before building?

Sorry for the message layout - I copied it from the output log.

@jmlzr

jmlzr commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

@wthaem Yes cmake will need to download a few packages via FetchContent. Can you check at the start of cmake output if that failed or something? If you run cmake directly it should normally already fail at that point though... If you had the build directory already before switching to this branch you could maybe try cmake with --fresh to force a reconfigure.

@kiozen

kiozen commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

same problem on a Linux machine. Even with cmake from scratch. The tracy header path is not set properly for the target.

@wthaem

wthaem commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

I'm starting the build always with cmake --fresh. Now, I deleted in a first step everything from the build directory, too. This changed the situation a bit: Some dependencies were obviously found (asmjit, blend2d, tracy). Now there appears -- Could NOT find rocprofiler-sdk (missing: rocprofiler-sdk_DIR) as new message. Configuring and generating is ok. But building fails again with a message similar to the one communicated yesterday:

FAILED: [code=2] src/qmaptool/CMakeFiles/qmaptool.dir/canvas/CCanvas.cpp.obj
C:\PROGRA~1\MICROS~1\18\COMMUN~1\VC\Tools\MSVC\1451~1.362\bin\Hostx64\x64\cl.exe  /nologo /TP -DAPPLICATION_NAME=qmaptool -DHELPPATH=doc/HTML -DQT_CORE_LIB -DQT_GUI_LIB -DQT_HELP_LIB -DQT_NETWORK_LIB -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_WIDGETS_LIB -DUNICODE -DVER_MAJOR=1 -DVER_MINOR=20 -DVER_STEP=3 -DVER_TWEAK="" -DWIN32 -DWIN64 -D_CRT_SECURE_NO_WARNINGS -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_UNICODE -D_WIN64 -ID:\QtProjects\QMS\QMS4Qt6\build-ninja\src\qmaptool -ID:\QtProjects\QMS\QMS4Qt6\src\qmaptool -ID:\QtProjects\QMS\QMS4Qt6\build-ninja\src\qmaptool\qmaptool_autogen\include -ID:\QtProjects\QMS\QMS4Qt6\src\qmaptool\. -ID:\QtProjects\QMS\QMS4Qt6\src\qmaptool\..\common -external:ID:\QtProjects\QMS\QMS4Qt6\build-ninja -external:Id:\QtProjects\QMS\GISInternals\1944_260614\release-1944-x64\include -external:Id:\QtProjects\QMS\GISInternals\1944_260614\release-1944-x64\include\proj9 -external:IC:\Qt\6.11.0\msvc2022_64\include\QtWidgets -external:IC:\Qt\6.11.0\msvc2022_64\include -external:IC:\Qt\6.11.0\msvc2022_64\include\QtCore -external:IC:\Qt\6.11.0\msvc2022_64\mkspecs\win32-msvc -external:IC:\Qt\6.11.0\msvc2022_64\include\QtGui -external:IC:\Qt\6.11.0\msvc2022_64\include\QtNetwork -external:IC:\Qt\6.11.0\msvc2022_64\include\QtHelp -external:IC:\Qt\6.11.0\msvc2022_64\include\QtSql -external:W0 /wd4996 /wd4101 /wd4005 /wd4003 /EHsc /O2 /Ob2 /DNDEBUG /Zi /GL -std:c++20 -MD /MP -Zc:__cplusplus -permissive- -utf-8 /showIncludes /Fosrc\qmaptool\CMakeFiles\qmaptool.dir\canvas\CCanvas.cpp.obj /Fdsrc\qmaptool\CMakeFiles\qmaptool.dir\ /FS -c D:\QtProjects\QMS\QMS4Qt6\src\qmaptool\canvas\CCanvas.cpp
D:\QtProjects\QMS\QMS4Qt6\src\qmaptool\canvas\CCanvas.cpp(22): fatal error C1083: Datei (Include) kann nicht geöffnet werden: "tracy/Tracy.hpp": No such file or directory
[320/831] Building CXX object src\qmaptool\CMakeFiles\qmaptool.dir\overlay\gridtool\CGridSelArea.cpp.obj
ninja: build stopped: subcommand failed.

The file Tracy.hpp can be found in the directory ...\build-ninja\_deps\tracy-src\public\tracy\Tracy.hpp.

Edit: ChatGPT info: "Does ROCprofiler-SDK exist on Windows?

Officially: no, not as a supported Windows package."

How to switch off the use of tracy?

My settings:

TRACY_ENABLE:BOOL=OFF

TRACY_ON_DEMAND:BOOL=OFF

jmlzr added 2 commits June 25, 2026 10:48
Add the profiler Tracy to the project and start instrumenting some
functions relevant to IMG rendering. With tracy turned off at compile
time this won't add any overhead.
Having a profiler available is essential to guide performance
improvements.
To use it turn on tracy with -DTRACY_ENABLE=1 then build the profiler
application itself, launch QMS and the profiler and connect it.
The tracy project will end in _deps/tracy-src inside the build dir.
Dramatically speed up IMG rendering by replacing the very slow Qt vector
engine with the much faster Blend2D for all but text rendering.
@jmlzr

jmlzr commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

I'm sorry I should have read your error message more carefully! Turns out I accidentally added an include to a qmaptool file (and qmaptool is not linked with Tracy). Since I always just built the qmapshack target I did not notice.

I fixed that by removing the include and confirmed that now all our targets build successfully.

You can ignore that missing rocprofiler. That's just an optional dependency of Tracy we don't need.

@wthaem

wthaem commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Now building is ok and nothing special noticed with a quick first test (KMz now again without blurry).

@jmlzr

jmlzr commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@wthaem did you maybe comment on the wrong PR? Because the blurry KMZ maps was something you noted in #1129 so it won't affect this branch yeah...

Did you try IMG maps? Noticed a performance improvement with those? Or visual issues?

@wthaem

wthaem commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Sure: the KMZ topic belongs to the other PR. But I noticed again the difference in quality with this PR.

I tried IMG maps and many types of raster maps. Loading, zooming, panning of IMGs was pretty quick. Image quality on my notebook screen quite good. My notebook has a good CPU!

@JFritzle

Copy link
Copy Markdown
Contributor

Currently, I am trying to build on macOS. I get tons of warnings like these:

/Users/user/qms1130/build_QMapShack/_deps/blend2d-src/blend2d/compression/deflatedecoder_p.h:281:5: warning: anonymous structs are a GNU extension [-Wgnu-anonymous-struct]
  281 |     struct {
      |     ^
/Users/user/qms1130/build_QMapShack/_deps/blend2d-src/blend2d/compression/deflatedecoder_p.h:285:5: warning: anonymous structs are a GNU extension [-Wgnu-anonymous-struct]
  285 |     struct {
      |     ^
/Users/user/qms1130/build_QMapShack/_deps/blend2d-src/blend2d/compression/deflatedecoder_p.h:281:5: warning: anonymous types declared in an anonymous union are an extension [-Wnested-anon-types]
  281 |     struct {
      |     ^
/Users/user/qms1130/build_QMapShack/_deps/blend2d-src/blend2d/compression/deflatedecoder_p.h:285:5: warning: anonymous types declared in an anonymous union are an extension [-Wnested-anon-types]
  285 |     struct {
      |     ^

Might it be possible to expand cmake configuration not to throw these warnings?

@jmlzr

jmlzr commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@JFritzle Pretty sure that's the same issue I already described in the PR description and Apple's clang just uses a different wording for that warning then GCC:

Btw the massive amount of ISO C++ prohibits anonymous structs warnings comes from the fact that our CMakeLists.txt unfortunately sets global compile options with add_compile_options that then affects subprojects as well. The better thing would be to set them only for our own targets with target_compile_options. But we can fix that if we get close to merging this, for now I didn't want to bother with that.

@JFritzle

Copy link
Copy Markdown
Contributor

Did not notice a performance improvement with map Reit_Wanderkarte_Italia_11_25.img on my Windows 11 PC:
Intel Core i5-2400 CPU, 4 logical processors, 22 GB RAM.

@kiozen

kiozen commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Haven't had the guts to deal with Tracy yet. But my hands-on experience is similar. On my high performance work laptop I can notice a small difference in performance. On my old private laptop no noticeable gain.

But on both machines I have to increase the details level quite a lot to get a noticeable lag. More than I usually would do. So the benefit is on the lower side

I am a bit undecided. Pulling in new dependencies is always a risk and makes me feel uneasy. On the other hand side I highly appreciate and acknowledge every work donated to QMapShack. This places me in between chairs. It's always a hard decision based on the estimated future of the feature. Will it cause more benefit than future trouble?

There is already quite some stuff I would like to get rid of (alglib, quazip) either by kicking out the feature or replacing it with native code. Dropping features is always trouble because of this one user popping up actually using it. And replacing code is another problem on it's own. For example what happens if I have to decide that blend2d can't be used anymore for whatever reason. I have to revert to Qt. Users might notice the performance loss and complain. Restoring the former code is possible. But might be more trouble than expected.

So there must be a benefit worth it. For example replacing the QMapShack native code with the Garmin SDK was a tough decision, too. Apart from a not 100% clarified license situation, it's now depending on Garmin's lib. On the other hand side, the native code was done ages ago by someone not reachable any more. The newer devices implement new features that require to actually notice the change (reported by users), understanding the rather complex code and fixing the stuff without breaking something. To get rid of this maintenance burden picking the Gamrin Lib was a choice.

So long story short: I am still undecided. Even after writing all of this.

@jmlzr

jmlzr commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

That's very strange. I guess you guys must be either using maps only in areas with very little features or have screens with low resolution if you don't have noticeable lag with the previous renderer.
On a 3840x2160 screen and with a AMD 5600G with details on 0 already the map feels sluggish on areas without that much going on. On areas with much going on - worst case a big city - it get very annoying (>=1s per update). If I turn details up it gets pretty much unusable.
I checked a Wanderreitkarte and that has even worse performance than a Freizeitkarte.

@kiozen I don't get your point tbh. If you ever wanna get rid of Blend2D you can just revert. It will only be used in the IMG renderer and that one is unmaintained since a while anyways, so not even like there is much of a chances of there being changes that then might need back porting. Most importantly: Why would a user complaining about performance in the future after a hypothetically possible revert matter more than one complaining now about current performance?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants