Adrian Page first coded an OpenGL-based canvas implementation for Krita in 2005. That was back in the Qt3 days. OpenGL was fairly simple back then, but we had to duplicate all our canvas handling code, once implemented in OpenGL, once implemented with QPainter.
Krita’s canvas code executes in three phases. There’s the image projection, that is, the result of combining all the layers, which is drawn first. Then we draw the canvas decorations: that’s the selection outline, the guides, the assistants, the reference images and so on. Then we draw the tool decorations: that’s the outline cursor, the line for the straight line or ruler tool and so on.
Obviously, implementing all of that twice, once in OpenGL, once with QPainter isn’t ideal.
The Good Days
So we were elated when Qt4 appeared. Qt4 came with an OpenGL based QPainter engine. This was ideal; we could split up our canvas code. The image would be drawn with pure OpenGL on a QGLWidget or with QPainter on a QWidget, and the canvas decorations and tool decorations would be drawn with QPainter on either canvas.
The Qt documentation even came with a nice example showing how this was to be done.
The First Fly in the Ointment
However, the Qt developers apparently saw the OpenGL QPainter engine more as a way to speed up the drawing of QWidgets than something that application developers would use. And the OpenGL QPainter engine never was able to render a complex application completely correctly.
So at some point, the engine stopped working on macOS. Mostly because Apple doesn’t want people to use OpenGL, so they’re starving their drivers from development, but also because the Qt developers thought that the OpenGL QPainter engine was a failed experiment because it didn’t improve performance when painting their widgets: they had forgotten that applications developers are using QPainter in their OpenGL applications. Or even told them not to do that. Though the documentation never reflected that opinion.
That sucked, since we needed it, and in 2016 we had to spend a Summer of Code slot on fixing the OpenGL QPainter engine so it worked on macOS with OpenGL 3.2 Core Profile. That landed in Qt.
R.I.P Touch UI for Krita
With the migration from Qt4 to Qt5 something else happened: Qt4 QML was based on QGraphicsView. I’ve always suspected that QGraphicsView was created for companies that needed mapping software, but in the Nokia days there were several attempts to use QGraphicsView as a basis for a mobile ui framework, DUI (best link I could find; there’s serious loss of history here).
Those attempts failed, until someone came up with QML, which initially was also rendered with QGraphicsView.
We used QML to create Krita Sketch and Krita Gemini. Because it was based on QGraphicsView, the touch ui we created worked seamlessly with our OpenGL-based canvas.
When Qt5 came out, QML was based on OpenGL and a scenegraph. We spent several months and quite a bit of money trying to integrate our OpenGL canvas in in the new scenegraph, but it just did not work. At all. It couldn’t be made to work, and Krita Sketch and Krita Gemini died.
(As an aside: it was much harder than we had expected to port our OpenGL code from Qt4 to Qt5. It was a huge hassle, in fact.)
The Next Episode
And then Google Chrome happened.
The quality of OpenGL drivers on Windows was always variable, sometimes even really bad. We had already encountered that when developing Krita Sketch, when we suddenly had a lot of Windows users.
Google encountered the same problems with Chrome, and they implemented a solution: Angle.
Angle seamlessly translates OpenGL into Direct3D. And once Chrome used that, all their crashes were gone.
And the GPU manufacturers had no reason all anymore to fix their drivers, so they didn’t. Games would use Direct3D, Chrome used Angle, and pretty soon Qt added an option to use Angle, too, because otherwise QML-based applications on Windows would keep crashing.
This was excellent news for us. We started using Angle, and the number of bug reports dropped a serious amount. And when we wanted to support HDR screens on Windows, the fact that we were using Angle already was great, because that enabled us to make HDR work, because on Windows, HDR can only be made to work when the window is rendered using Direct3D.
The HDR patches still haven’t landed in Qt, so we are carrying them, along with a lot of other patches that are needed to make Krita work well.
We regularly port those patches to newer versions of Qt5, but we make all our Krita binary builds with Qt 5.12, because every version of Qt since 5.12 has been too buggy to use. For example: with 5.15, using a QMdiArea in subwindow mode will hang on Windows.
Except for the fact that Krita Sketch was still dead, and we were porting to Android, and a mobile UI would have been nice, everything was fine.
Qt6 Drops Angle
Because, obviously, Qt’s Angle build option only existed to make sure that QML apps would work on Windows, not for anything, Qt6 has dropped the Angle option…
Because there’s going to be a new framework which will use the various GPU API’s (Metal, Vulkan, Direct3D, OpenGL) directly with a abstraction layer ( ) above them that will be used to render the QML scenegraph: RHI. It looks like that’s all internal to Qt, though.
It’s really hard to find documentation, but it looks like QPainter will render using those modules; but what isn’t clear is what will happen when we’re going to use QPainter on a QOpenGLWidget. Or would we have to implement a Metal canvas, a Direct3 canvas, and an OpenGL canvas? And will we be able to access the HDR functionality on Windows?
Or should we just patch Qt6 so it can be built with Angle again?
This blog post appeared on hackernews, and one of the reactions (the one I linked to) was really helpful: Jean-Michaël Celerier has actually implemented something outside Qt, using Qt’s RHI interface. So that is possible! Even though the documentation says “Aim to be a product – and in the bigger picture, part of a product (Qt) – that is usable out of the box both by internal (such as, Qt Quick) and, eventually, external users.”
So, I guess the choice for Krita boils down to using RHI — after we’ve determined that it is possible to use that, or using Angle.
In both cases we would be running an abstraction on top of Metal, Direct3D, OpenGL or Vulkan. In the first case, we’d tie Krita even closer to Qt (and every Qt major release changes its approach to graphics, so in a couple of years, who knows…) In the second case, we will have to maintain patches against Qt.
We haven’t come to a conclusion yet.