[quick feed needed] Does Krita need openGL rendering backend on Windows?

Indeed! Disabling the news allowed it to start. :+1: Unfortunately, I was unable to get ANGLE to use OpenGL. I was able to select either native OpenGL or D3D11 via ANGLE (Auto or ANGLE). My hardware info looked like this:

  Vendor:  "Google Inc. (AMD)" 
  Renderer:  "ANGLE (AMD, AMD Radeon RX 7900 XTX Direct3D11 vs_5_0 ps_5_0, D3D11-32.0.13031.3015)" 
  Driver version:  "OpenGL ES 3.0.0 (ANGLE 2.1.0 git hash: f2280c0c5f93+krita_qt5)" 
  Shading language:  "OpenGL ES GLSL ES 3.00 (ANGLE 2.1.0 git hash: f2280c0c5f93+krita_qt5)" 

Nevertheless, I looked at the performance just a bit.

Using this 6.0 build

In DX11 mode I’m getting around 154 FPS while drawing with a mouse, or 180 FPS while drawing with a pen. My display refresh rate is 144Hz. I didn’t notice any meaningful difference compared to native OpenGL. Canvas rotation/panning/zooming is noticeably slower about 50-75 FPS.

Using a 5.3 nightly build (ab63c9f)

In OpenGL mode I’m getting 200-300 FPS while rotating/panning/zooming the canvas, and mouse is even faster. Painting with a brush is consistently 250+ FPS or even 400+ FPS with a mouse. DX11 felt very similar, I couldn’t tell if it’s faster or slower.

In short, it does feel that 5.3 is performing significantly better than the 6.0.


Going back to the 6.0 build, I noticed several glitches:

  • Disabling the start page news fixed the crash!
  • The start page thumbnail look a bit blurry
  • Creating or opening a document causes
    SAFE ASSERT (krita): “d->settings” in file C:/dev/env-14/krita/libs/image/brushengine/kis_paintop_preset.cpp, line 531
    When ignored, a safe assert in line 554, then it ping-pongs like that for a few times and eventually it goes away
  • Subwindow title is duplicated, causing blurry text
  • It’s impossible to open the top bar menus (like Settings) with a pen, it closes immediately. Mouse is OK
  • Plugins don’t work (I guess are disabled?)

According to the backtrace, the news widget causes some call to QTimeZone. On Qt6, QTimeZone on Windows now uses ICU, which seems to explain the regression. No idea why ICU crashes, though…

I think this is caused by an issue loading the XML of certain presets (see MR!2352), though I’ve only seen the pair of safe asserts with presets in bundles.

Krita 6 isn’t ported to PyQt6 (yet).


I did a slight bit of testing of this package, the performance of ANGLE and OpenGL seemed similar. I didn’t compare it to 5.x. When painting I got maybe 40-60 FPS (59.9Hz display), with usually around 9%-15% frame drops according to the log. When zooming or panning more like 20FPS. (Not great, but my Windows machine is falling apart a bit.)

Hi, @YHR!

How did you measure this FPS? Using Krita’s internal widget or using some GPU driver’s tools?

I mean, the patch in Qt6 intentionally limits the framerate to “maximum framerate of available displays”. It means that, theoretically, the FPS value should not get higher 144 in your case :slight_smile:

That sounds greatly confusing. What FPS limit do you have set in Krita settings? Default value is 100FPS and the framerate while painting should not get higher than that.

I just used Krita built-in FPS counter (Performance > Debug logging of OpenGL framerate). However, I think this counter is busted :smiley: I just tried the latest nightly on another PC and I’m getting up to 4000 FPS now :stuck_out_tongue:

I don’t know if I changed the FPS limit on my other PC, but testing now it was at 100 FPS. Honestly, I didn’t even realize there was a slider like this. Also, I see Krita needs to be restarted for this limiter to kick in. I confirmed 20 FPS works, it just doesn’t affect the FPS counter displayed on the canvas.

I guess I should look for an alternative way to measure FPS. I can get a measurement with the driver built-in overlay, but it only works if Krita goes fullscreen (canvas only mode with title bar hidden). In this case the FPS varies a lot (due to inconsistent updates) but can go up to 1000 while painting so there’s no practical limit (the driver overlay FPS, I mean). I can test the 6.0 build a bit more in the evening.

1 Like

That sounds crazy, we’ll need to find out what happens there :slight_smile:

1 Like

Btw, @YRH, if you stop looking at the FPS numbers, do you also feel that 5.3 performs better than 6.0? Does it feel more responsive?

It depends. I feel like any canvas transformations: panning, rotation, and scaling are worse. They are a bit more choppy, and especially the panning looks blurry. However, it may not be that perceptible.

To be sure, I also tested fullscreen (canvas only) mode with Radeon driver metrics overlay that shows FPS. The difference between 5.3 and 6.0 is substantial. In 5.3 I’m usually getting up to 250 FPS, but in 6.0 it can be as low as 50 FPS. I think this is why it feels choppy and blurry. I suspect it’s an issue with frame pacing, because the GPU is almost idle in either version. I was doing all these tests in OpenGL mode.

As for brush stroke painting, it honestly felt the same in both versions. I set the frame limit to 300 FPS in the settings, and it was likewise smooth.

Hi, @YRH!

Could you do a small test for me with that 6.0 version?

  1. Open DebugView and keep it open

  2. Open terminal

  3. Change to the directory with the unpacked krita:

    cd c:\path\to\krita-6.0.0-prealpha-angle-perf-dk1\bin
    
  4. Set a special environment variable to enable debugging:

    set QT_LOGGING_RULES=qt.widgets.painting=true
    
  5. Type krita.exe (not krita or krita.com, because the terminal will not fit this amount of debugging)

  6. When Krita starts check DebugView and find a line that looks like that (it should be at the top of the log):

    [18996] qt.widgets.painting: QWidgetRepaintManager: Selecting screen refresh rate 60 fps
    

What refresh rate is selected in this line? If you moved Krita between the screens, try to search for “refresh rate” in DebugView and find all messages like that.

I ran Krita and DebugView on the same monitor. All lines show 144Hz, which matches my display setting in Windows.

00000007	0.12746350	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00000221	1.30320275	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00004693	9.33808136	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00005184	9.38907433	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00006231	9.57254410	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00007354	14.28299236	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00007675	15.04733276	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00007898	15.12550735	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00008515	15.81152916	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00013260	18.65022469	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00021153	27.42217636	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00041063	36.80591965	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	
00103926	54.44150925	[4280] QWidgetRepaintManager: selected screen refresh rate 144 fps	

EDIT: I set my other monitor to 60Hz, and even started Krita on that second monitor, but the log only ever shows 144Hz. So it seems it takes it from the main display.
Also, when I tried closing and opening the document again, it crashed:

* thread #1, stop reason = Exception 0xc0000005 encountered at address 0x7fffc511c332: Access violation reading location 0xffffffffffffffff
  * frame #0: 0x00007fffc511c332 Qt6OpenGL.dll`QOpenGL2PaintEngineEx::beginNativePainting() + 706
    frame #1: 0x00007fffd2927209 libkritaui.dll`KisTool::paintToolOutline(QPainter*, KisOptimizedBrushOutline const&) + 89
    frame #2: 0x00007fffd293fc7f libkritaui.dll`KisToolPaint::paint(QPainter&, KoViewConverter const&) + 303
    frame #3: 0x00007fffd26470c6 libkritaui.dll`KisCanvasWidgetBase::drawDecorations(QPainter&, QRect const&) const + 870
    frame #4: 0x00007fffd28f5b17 libkritaui.dll`KisOpenGLCanvas2::paintGL() + 503
    frame #5: 0x00007ffff3812c68 Qt6OpenGLWidgets.dll`QOpenGLWidgetPrivate::render() + 968
    frame #6: 0x00007fffd28f5e11 libkritaui.dll`KisOpenGLCanvas2::paintEvent(QPaintEvent*) + 305
    frame #7: 0x00007fffc69e3d41 Qt6Widgets.dll`QWidget::event(QEvent*) + 2225
    frame #8: 0x00007ffff38143d4 Qt6OpenGLWidgets.dll`QOpenGLWidget::event(QEvent*) + 516
    frame #9: 0x00007fffc6989c1b Qt6Widgets.dll`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 315
    frame #10: 0x00007fffc698ac49 Qt6Widgets.dll`QApplication::notify(QObject*, QEvent*) + 601
    frame #11: 0x00007fffd2bcd1ba libkritaui.dll`KisApplication::notify(QObject*, QEvent*) + 170
    frame #12: 0x00007fffd135e618 Qt6Core.dll`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 200
    frame #13: 0x00007fffc69da7e6 Qt6Widgets.dll`QWidgetPrivate::sendPaintEvent(QRegion const&) + 86
    frame #14: 0x00007ffff3813cec Qt6OpenGLWidgets.dll`QOpenGLWidget::resizeEvent(QResizeEvent*) + 268
    frame #15: 0x00007fffc69e3ab1 Qt6Widgets.dll`QWidget::event(QEvent*) + 1569
    frame #16: 0x00007ffff38143d4 Qt6OpenGLWidgets.dll`QOpenGLWidget::event(QEvent*) + 516
    frame #17: 0x00007fffc6989c1b Qt6Widgets.dll`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 315
    frame #18: 0x00007fffc698ac49 Qt6Widgets.dll`QApplication::notify(QObject*, QEvent*) + 601
    frame #19: 0x00007fffd2bcd1ba libkritaui.dll`KisApplication::notify(QObject*, QEvent*) + 170
    frame #20: 0x00007fffd135e618 Qt6Core.dll`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 200
    frame #21: 0x00007fffc69da6d6 Qt6Widgets.dll`QWidgetPrivate::sendPendingMoveAndResizeEvents(bool, bool) + 342
    frame #22: 0x00007fffc69e0e63 Qt6Widgets.dll`QWidgetPrivate::show_helper() + 67
    frame #23: 0x00007fffc69e165f Qt6Widgets.dll`QWidgetPrivate::showChildren(bool) + 1295
    frame #24: 0x00007fffc69e0e84 Qt6Widgets.dll`QWidgetPrivate::show_helper() + 100
    frame #25: 0x00007fffc69e2f79 Qt6Widgets.dll`QWidgetPrivate::setVisible(bool) + 1577
    frame #26: 0x00007fffc69e2695 Qt6Widgets.dll`QWidget::setVisible(bool) + 821
    frame #27: 0x00007fffc69e164a Qt6Widgets.dll`QWidgetPrivate::showChildren(bool) + 1274
    frame #28: 0x00007fffc69e0e84 Qt6Widgets.dll`QWidgetPrivate::show_helper() + 100
    frame #29: 0x00007fffc69e2f79 Qt6Widgets.dll`QWidgetPrivate::setVisible(bool) + 1577
    frame #30: 0x00007fffc69e2695 Qt6Widgets.dll`QWidget::setVisible(bool) + 821
    frame #31: 0x00007fffc69e164a Qt6Widgets.dll`QWidgetPrivate::showChildren(bool) + 1274
    frame #32: 0x00007fffc69e0e84 Qt6Widgets.dll`QWidgetPrivate::show_helper() + 100
    frame #33: 0x00007fffc69e2f79 Qt6Widgets.dll`QWidgetPrivate::setVisible(bool) + 1577
    frame #34: 0x00007fffc69e2695 Qt6Widgets.dll`QWidget::setVisible(bool) + 821
    frame #35: 0x00007fffc69e164a Qt6Widgets.dll`QWidgetPrivate::showChildren(bool) + 1274
    frame #36: 0x00007fffc69e0e84 Qt6Widgets.dll`QWidgetPrivate::show_helper() + 100
    frame #37: 0x00007fffc69e2f79 Qt6Widgets.dll`QWidgetPrivate::setVisible(bool) + 1577
    frame #38: 0x00007fffc69e2695 Qt6Widgets.dll`QWidget::setVisible(bool) + 821
    frame #39: 0x00007fffc6b6db68 Qt6Widgets.dll`QMdiSubWindow::changeEvent(QEvent*) + 312
    frame #40: 0x00007fffc69e350b Qt6Widgets.dll`QWidget::event(QEvent*) + 123
    frame #41: 0x00007fffc6b6d710 Qt6Widgets.dll`QMdiSubWindow::event(QEvent*) + 2000
    frame #42: 0x00007fffc6989c1b Qt6Widgets.dll`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 315
    frame #43: 0x00007fffc698ac49 Qt6Widgets.dll`QApplication::notify(QObject*, QEvent*) + 601
    frame #44: 0x00007fffd2bcd1ba libkritaui.dll`KisApplication::notify(QObject*, QEvent*) + 170
    frame #45: 0x00007fffd135e618 Qt6Core.dll`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 200
    frame #46: 0x00007fffc69d5169 Qt6Widgets.dll`QWidget::setWindowState(QFlags<Qt::WindowState>) + 473
    frame #47: 0x00007fffd2c1c18d libkritaui.dll`KisMainWindow::showView(KisView*, QMdiSubWindow*) + 285
    frame #48: 0x00007fffd2c1bfa7 libkritaui.dll`KisMainWindow::addView(KisView*, QMdiSubWindow*) + 167
    frame #49: 0x00007fffd2c1e351 libkritaui.dll`KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument*, QMdiSubWindow*) + 145
    frame #50: 0x00007fffd2c1e7b9 libkritaui.dll`KisMainWindow::slotLoadCompleted() + 153
    frame #51: 0x00007fffd13b6f9d Qt6Core.dll`void doActivate<false>(QObject*, int, void**) + 1629
    frame #52: 0x00007fffd2beb1f9 libkritaui.dll`KisDocument::openPathInternal(QString const&) + 633
    frame #53: 0x00007fffd2beaa7f libkritaui.dll`KisDocument::openPath(QString const&, QFlags<KisDocument::OpenFlag>) + 1311
    frame #54: 0x00007fffd2c1d995 libkritaui.dll`KisMainWindow::openDocumentInternal(QString const&, QFlags<KisMainWindow::OpenFlag>) + 261
    frame #55: 0x00007fffd2c1d683 libkritaui.dll`KisMainWindow::openDocument(QString const&, QFlags<KisMainWindow::OpenFlag>) + 115
    frame #56: 0x00007fffd28da4d3 libkritaui.dll`KisWelcomePageWidget::recentDocumentClicked(QModelIndex) + 115
    frame #57: 0x00007fffd25f820a libkritaui.dll`KisWelcomePageWidget::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 426
    frame #58: 0x00007fffd13b6f9d Qt6Core.dll`void doActivate<false>(QObject*, int, void**) + 1629
    frame #59: 0x00007fffc6c893a3 Qt6Widgets.dll`QAbstractItemView::mouseReleaseEvent(QMouseEvent*) + 963
    frame #60: 0x00007fffc6cc9d5d Qt6Widgets.dll`QListView::mouseReleaseEvent(QMouseEvent*) + 45
    frame #61: 0x00007fffc69e3d62 Qt6Widgets.dll`QWidget::event(QEvent*) + 2258
    frame #62: 0x00007fffc6a8518c Qt6Widgets.dll`QFrame::event(QEvent*) + 44
    frame #63: 0x00007fffc6c87f52 Qt6Widgets.dll`QAbstractItemView::viewportEvent(QEvent*) + 1554
    frame #64: 0x00007fffd135e9a0 Qt6Core.dll`QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 272
    frame #65: 0x00007fffc6989c07 Qt6Widgets.dll`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 295
    frame #66: 0x00007fffc698c4f5 Qt6Widgets.dll`QApplication::notify(QObject*, QEvent*) + 6917
    frame #67: 0x00007fffd2bcd1ba libkritaui.dll`KisApplication::notify(QObject*, QEvent*) + 170
    frame #68: 0x00007fffd135e618 Qt6Core.dll`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 200
    frame #69: 0x00007fffc698a235 Qt6Widgets.dll`QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool, bool) + 837
    frame #70: 0x00007fffc6a00a2e Qt6Widgets.dll`QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1502
    frame #71: 0x00007fffc69ffc45 Qt6Widgets.dll`QWidgetWindow::event(QEvent*) + 117
    frame #72: 0x00007fffc6989c1b Qt6Widgets.dll`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 315
    frame #73: 0x00007fffc698ac49 Qt6Widgets.dll`QApplication::notify(QObject*, QEvent*) + 601
    frame #74: 0x00007fffd2bcd1ba libkritaui.dll`KisApplication::notify(QObject*, QEvent*) + 170
    frame #75: 0x00007fffd135e618 Qt6Core.dll`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 200
    frame #76: 0x00007fffc623fd04 Qt6Gui.dll`QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2500
    frame #77: 0x00007fffc62afb8a Qt6Gui.dll`QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 458
    frame #78: 0x00007fffd1511350 Qt6Core.dll`QEventDispatcherWin32::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 96
    frame #79: 0x00007fffc660efe9 Qt6Gui.dll`QWindowsGuiEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 25
    frame #80: 0x00007fffd1369baa Qt6Core.dll`QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 1194
    frame #81: 0x00007fffd135ee03 Qt6Core.dll`QCoreApplication::exec() + 147
    frame #82: 0x00007fffd306767a krita.dll`krita_main + 25162
    frame #83: 0x00007ff797ca1311 krita.exe`__tmainCRTStartup + 433
    frame #84: 0x00007ff797ca1156 krita.exe`.l_startw + 18
    frame #85: 0x00007ff865cce8d7 kernel32.dll`BaseThreadInitThunk + 23
    frame #86: 0x00007ff8670fbf6c ntdll.dll`RtlUserThreadStart + 44

EDIT: I set my other monitor to 60Hz, and even started Krita on that second monitor, but the log only ever shows 144Hz. So it seems it takes it from the main display.

It scans all the available displays to the application and selects the maximum FPS, because on this level of code (composer) we don’t really know which display the window belongs :slight_smile:

So to change the detection result you have to change the refresh rate on all the available displays in the system.

UPD:
Anyway, it seems like the detection works fine :slight_smile: It is only rendering that is slow for some reason :slight_smile:

1 Like

I did a test with 5.2.9, 5.3 and 6.0 on a Windows 10 notebook with its native display.

Refresh rate is correctly recognized (59.xx fps).

I set Krita performance to use max. 60 fps.

in all three Krita versions there is no obvious difference in painting speed.
OpenGL, Direct3D via Angle and Acceleration=Off are similar.

Layer translation, rotation, scaling is much slower with Acceleration=Off.

Blur or Gaussian Blur filter kills performance immediately (painting and transformations becomes laggy and stuttering). The higher the blur pixel value the worse it gets.

Thanks, @cgidesign!

What version of Krita 6.0 you used? Some published one or from nightlies? The last published version should have a small issue: a significant delay when opening any native window (e.g. a menu or a tooltip). The nightly version should have this issue fixed (though there is some issue with windows nightlies right now).

@dkazakov I took the one you linked some posts above:

Hehe, okay :slight_smile: This package should still have some delay on the window creation… It is interesting that you didn’t see the delay (might be related to the way how your GPU compiles shaders).

Here is the latest nightly build, btw. It should have this “native window creation” issue fixed:

In case it is relevant, I just crosschecked the window creation on the “old” V6. I don’t see a delay. E.g. opening menus or filter settings is instant. Also opening a menu e.g. file and then moving the mouse to the right over the other menus opens them instantly.
The speed of window, menu etc. opening with the “new” V6 you posted, is the same like with the “old” on my system.

Just reporting here for visibility – I found the source of the bad performance! It’s the canvas rulers!

Although it’s difficult to reliably measure the performance, I could tell that the “feel” of the canvas operations was much smoother if the rulers were disabled. I tested my own 6.0 build as well as Dmitry’s build linked here, and boy, it looked buttery smooth with the rulers hidden.

EDIT: There’s no difference in how Krita 5.3 and 6.0 handle the rulers. The expensive update is KoRuler::setOffset, which gets spammed 10+ times every smallest canvas update. That’s like 300 updates per second when the canvas is being panned, for example. The only thing is that these same updates are more expensive in Qt6.

It seems to me like the UI is just slower in general in the Qt6 build, and the rulers are just one place where it gets extreme due to the number of updates.

Interesting, I tried it as well but don’t see an obvious difference regardless of whether rulers and rulers track pointer are on or off (5.2.9, 5.3, 6.0).
But I am testing without a pen tablet or pen display. I only use the trackpad of the notebook. Maybe that is different on your side.

It may be only noticeable on a high refresh display actually. I tried it with 60Hz and indeed I can’t tell the difference. But on 144Hz (or I imagine, higher values too) it will show as ever so slight stutter during canvas transformation.

1 Like

Out of curiosity,

does it make sense to document more performance tests or should we wait for final Krita 5.3 or even 6.0?

Edit: deleted (I made a new post instead of editing this one)