What makes Krita's canvas operations feel so "wrong"?

Don’t get me wrong, I’m not trying to be vague, vagueness just so happens to be all I’ve gotten out of this whole adventure.

This started as a bug report almost 2 years ago. The canvas operations like zoom, pan, rotate, etc, have all made leaps and bounds since then. I’m tremendously glad I managed to help get that fixed when I did as I’ve probably used Krita a good thousand+ hours since then. Anyway, to the point.

I don’t know how to explain it. Panning, rotating, and zooming in Krita feels wrong. (Mainly panning/zooming). It’s nowhere near bad enough that I’d consider it a bug (like it was), but it’s something I’ve gotten obsessive over recently because of a friend’s negative reaction toward it as I tried to get him to move to Krita, and the worst part is I can’t figure out why it happens.

When I test the canvas movement tools in other programs, most of them feel ‘good’, the best way I can describe it is that it feels like the rendering of each frame is planned. With Krita, it almost feels like it just sort of spits them out as it gets them with a complete disregard for the timing of the previous frames, the next one, or the refresh rate of the monitor.

This can be good, by using this method, Krita can output hella framerates, usually hitting 300+ for me. So why does it feel so choppy? When my friend tries these operations on his 160hz monitor, he says they are godly smooth, but he says he notices the ‘inconsistency’ on his 60hz. I personally don’t get the 160hz experience, as my Cintiq (and no drawing tablet as far as I know) gets over 60hz currently.

I originally started investigating into why this is recently, and began writing another ‘bug’ report which was mainly a suggestion. But as I dove into it, the more confused I became. I recorded 1000fps footage of my screen while panning, I recorded 60FPS screencaps of all the programs, logged frame timings, messed with various GPU’s on various computers using various VSync settings, plotted positions of the canvas during pans, wrote scripts to programmatically pan the canvas in perfect circles, I went the full 9 yards. Yet I couldn’t come up with any major hard numbers to support my bug report, and I knew that would mean skepticism, so I’m turning here instead.

I could see it with my eyes, I’ve stared at that canvas long enough in my career to tell it’s different. The first thing my friend said as I managed to get him to switch to Krita was that it felt laggy, despite his fps readout being 130+fps. To make sure I wasn’t crazy I set up some blind studies, where I showed various artist friends recordings of me panning around a blank canvas with anything cropped that would indicate which program was which. They all successfully pointed out that one was smoother than the other.

So I turned the bug report into this thread, calling other artists to see if anyone else notices this. I know it may not bother you, since I know I’m a stickler for this sort of stuff, but I’d still like to know if you notice it when directly compared to other programs. You can turn on your FPS counter in performance settings->Debug logging of OpenGL framerate. Does it feel like you’re getting 60fps even though your reported framerates are probably much higher?

I’m also going to be using this thread to post any recordings or logs or anything I manage to find while looking deeper into this. Thanks to the devs for all their hard work, and thanks everyone else for the support of the program. I truly think we can all make it better than it already is.

5 Likes

Just to be sure: it’s not about zoom having low amounts of levels (25-33-50-66-100)?

What I noticed while playing with the FPS counter is that while just moving a mouse I get 45-60 fps, but while panning or zooming I get lower FPS, maybe 20 for zooming and 30 for panning. It’s still pretty much random though (and as you can see, quite low - but my laptop is admittedly not very good), low values can happen for moving the cursor and high values can happen for panning. Can you maybe check if you see any differences like that on your system?

Heya, I use relative zoom mode, so I hold R and drag my pen to zoom in/out, the canvas doesn’t use steps or update at discrete zoom levels.

Just tested it, and on average I get around 120 fps reported by OpenGL for pan/rotate/zoom, and never see it drop below 60.

Comparison, from top to bottom: SAI2, Photoshop CC, ClipStudioPaint, Paintstorm Studio, Krita, GIMP. Please note the movements may not be timed the same.

I don’t know what I expected to get out of these comparisons but I don’t think I found it.

Alright last one of these, this time I controlled for time with a pilot 1-frame movement that got recorded by an external mouse position tracker.

Still no closer to understanding the problem

2 Likes

Aha, seems the issue only crops up when dragging with the Tablet pen. Could potentially be something to do with the polling rate?

You can see the frames that are “mistimed”

2 Likes

Yeah, I can feel a difference between Krita and CSP scaling. Something about the “anchor” or “pull” of each feels different.

I can’t do any comparison except between GIMP and Krita.

On my side I don’t really see differences between both software
Both have vsync flickering when pan/rotate/zoom the canvas.

And I’m wondering if problem is relative to my graphic card drivers more than software :thinking:

Grum999

Doing tests on my laptop, I have no problems.
Everything is smooth, no vsync flickering like I have on my workstation.

But my workstation have a better CPU, and really better GPU.

Can’t understand why there’s a such difference between both computers
By being able to compare them and to see the difference, I can understand if someone have the same result than my workstation and is used to have something like I currently have on my laptop, that Krita’s canvas can be a problem.

But not able to understand why there’s a such difference :-/

Grum999

I do feel like it has something to do with what hardware configuration is being used. Similarly, I upgraded my PC recently to quite literally the best hardware money can buy, and I still get stuttering with Krita.

I wish there was a way to narrow down why exactly some have the problem and others don’t. I’m currently in the middle of installing Ubuntu 20 to see if it works any better. (I had Ubuntu 21 dual booted but I couldn’t find any working Nvidia drivers that didn’t crash the system shortly after GRUB and XServer only got me 20fps on Krita operations)

1 Like

Maybe this is an easier way to look at it, here is a raw video recording that’s been stabilized to the cursor position. You can see how the canvas jitters in relation to the actual cursor
No VSync No triple buffering:


VSync on, triple buffering on:

Without vsync it seems better? :thinking:

Like you, I have a nvidia on my workstation on which result is bad:

OpenGL Info
 
  Vendor:  "NVIDIA Corporation" 
  Renderer:  "GeForce GTX 1060 3GB/PCIe/SSE2" 
  Version:  "4.6.0 NVIDIA 418.197.02" 
  Shading language:  "4.60 NVIDIA" 
  Requested format:  QSurfaceFormat(version 3.0, options QFlags<QSurfaceFormat::FormatOption>(DeprecatedFunctions), depthBufferSize 24, redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize 8, stencilBufferSize 8, samples -1, swapBehavior QSurfaceFormat::DoubleBuffer, swapInterval 0, colorSpace QSurfaceFormat::DefaultColorSpace, profile  QSurfaceFormat::CompatibilityProfile) 
  Current format:    QSurfaceFormat(version 4.6, options QFlags<QSurfaceFormat::FormatOption>(DeprecatedFunctions), depthBufferSize 24, redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize 8, stencilBufferSize 8, samples -1, swapBehavior QSurfaceFormat::DoubleBuffer, swapInterval 0, colorSpace QSurfaceFormat::DefaultColorSpace, profile  QSurfaceFormat::CompatibilityProfile) 
     Version: 4.6
     Supports deprecated functions true 
     is OpenGL ES: false 

On my laptop on which everything is smooth, I have a not really powerfull intel graphic card…
:confused:

I’m using nvidia proprietary drivers…

Grum999

Alright, I’ve managed to test panning/zooming on Ubuntu 21 and Pop! OS 20, same issue.

just to confirm, does the stuttering also occur when hardware acceleration is turned off?

When software renderer is on, the FPS is much lower than the refresh rate. But from what I can tell, yes, the timing of when the canvas is rendered is inconsistent:

Actually- no, my bad. Software renderer doesn’t seem to have the same issue. I don’t see any doubling up or (very) inconsistent frame render timings. Of course this isn’t a solution because it’s still only getting ~18 FPS

1 Like

I think I cracked it. It only happens when using a Pro Pen 2 from Wacom on my end. As to why? It could be a couple reasons.
The pro pen 2 introduced several improvements, and one of them was a higher polling rate. The pen driver would report position more times per second. Perhaps this is throwing out the panning distance calculations? Could also be a lower polling rate, my Cintiq is 185hz and my mouse is 1000 (or 125 for testing).
Another thing could be Wacom’s drivers are bad, but I don’t need to tell you that. The only argument against that is Krita is the only program I can find that suffers this badly from them.
It’s extremely obvious here, where I overlay all the frames and compare them mouse vs tablet panning.



I have an idea, with my limited programming knowledge and having never looked at the source code:
I think that when Krita wants to draw the next frame of panning, the first thing it does is ask for the last reported position of the mouse cursor.
Depending on when it calls for that position in relation to the last time the mouse polled, this may be several milliseconds in the past, or less than a millisecond. Since these aren’t synced, it created the gaps we see.
Now why does it work with a 1000hz mouse smoothly?
Because when Krita wants to draw the next frame and asks for the last mouse position, it will always get one less than a millisecond in the past and this inconsistency no longer exists.

I have opened a bug report at 439106 – Low pointer polling rates cause inconsistent frame 'timings' in functions tied to pointer movement.

5 Likes

great to hear we mightve found a cause!
fingers crossed the devs will be able to patch this up but iirc kritas pen support isn’t custom written. in that case its possible that its an inherent issue with qt.

1 Like

I’ve done a lot of theorycrafting, and came out with these two concepts for what I think is happening:
Comparing 1000hz to 125hz:


If Krita’s internal FPS is unlocked:

3 Likes

The leading solution concept to this is theoretically simple albeit very difficult. I have more concepts, but this seems the most doable though extremely technical.

The first thing you’d have to do is turn vsync on for Krita. This is the easy part as on Nvidia GPUs this is the default. This will force Krita to only render frames after the previous frame has been written from buffer. This theory would also work for non-v-sync, but might be slightly more erratic.

Turning on VSync will naturally introduce a slight delay of about 1 frame.

In the background, asynchronously, a pointer pseudoposition function is constantly receiving inputs from the actual pointer. It keeps the last 2 (or more if you’re a math major) of these positions and timings in-memory for later reference.

At any point in time that an action requires an ‘up to date’ and ‘consistent’ but not necessarily extremely accurate pointer position, such as for panning, zooming, rotating, etc, instead of grabbing the current pointer position, it calls the pointerPseudoposition function.

This function grabs the current microtime, and extrapolates a ‘current’ pointer position given the previous 2 mouse positions and microtime. I’d imagine the math would look something like:

x1 = last known x position
x2 = last x position before x1
y1 = last known y position
y2 = last y position before y1
time1 = time int in microseconds of last known pointer input
time2 = time int in microseconds of previously known pointer input before time1
currentTime = the microseconds of when the function is called

newX = x1 + ( (currentTime - time1) / (time1 - time2) * (x1 - x2))
newY = y1 + ( (currentTime - time1) / (time1 - time2) * (y1 - y2))

This will output an X and Y position of the ‘mouse’ which should slot perfectly into whatever function the current pan/rotate/zoom function uses when it calls for the mouse position.

This will cause slightly weird behavior if the pointer changes directions instantaneously, but for natural movements such as tablet pens, this could be a lifesaver. Perhaps it could be a toggle-able feature called ‘polling rate compensation’.

1 Like