Bug 439106 - Low pointer polling rates cause inconsistent frame 'timings' in functions tied to pointer movement.
Summary: Low pointer polling rates cause inconsistent frame 'timings' in functions tie...
Status: RESOLVED FIXED
Alias: None
Product: krita
Classification: Applications
Component: OpenGL Canvas (other bugs)
Version First Reported In: nightly build (please specify the git hash!)
Platform: Microsoft Windows Microsoft Windows
: NOR normal
Target Milestone: ---
Assignee: Krita Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-06-24 09:33 UTC by Ralek Kolemios
Modified: 2021-09-09 13:24 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In:
Sentry Crash Report:


Attachments
Timelapse of a canvas pan using various input methods (42.75 KB, image/png)
2021-06-24 09:33 UTC, Ralek Kolemios
Details
polling rate comparison (335.60 KB, image/png)
2021-06-25 01:44 UTC, Ralek Kolemios
Details
Proposed fix (458.56 KB, image/png)
2021-06-25 04:29 UTC, Ralek Kolemios
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ralek Kolemios 2021-06-24 09:33:19 UTC
Created attachment 139637 [details]
Timelapse of a canvas pan using various input methods

4.4.7-alpha (git 4e4db6a) but is likely widespread.

This originally started with bug #409460

I believe that low (<200hz) polling rates in pointer devices causes Krita to receive outdated pointer positions. These outdated positions are taken as truth, and operations such as panning, zooming, and rotating suffer because of it. This causes a weird off-time stuttering seen in the attached images.

Attached are several timelapse images of me panning a small canvas across the screen with various devices of different polling rates. I noticed that regardless of device type, the one factor that most closely aligned with the stuttering was that the device polling rate was low.

If I had to make an educated guess as an artist and by no means a developer, I feel like when Krita begins to draw a new frame, it asks for the last recorded pointer position. When the pointer's location is updated once every 8ms (125hz, middle-grade Cintiq), this position may be anywhere from 1-8ms old. This causes the stuttering shown in the pictures.

On the other hand, when device polling rate is high, such as 1000hz, I believe Krita always receives a <1ms old pointer position, and the problem disappears.

I believe fixing this issue one way or the other will be beneficial to myself and other artists, as nearly every tablet on the market polls at around ~100hz, with only top of the line models reaching near 180hz, which still isn't high enough to avoid this issue.

A thread was started at https://krita-artists.org/t/what-makes-kritas-canvas-operations-feel-so-wrong/25377 as I was trying to figure out what exactly was causing the issue before filing the bug report, but most necessary information has been condensed into this report.
Comment 1 Ralek Kolemios 2021-06-25 01:44:21 UTC
Created attachment 139651 [details]
polling rate comparison

A graphic describing why I believe this issue happens.
Comment 2 Ralek Kolemios 2021-06-25 04:29:07 UTC
Created attachment 139652 [details]
Proposed fix

Text taken from https://krita-artists.org/t/what-makes-kritas-canvas-operations-feel-so-wrong/25377/20?u=ralek

My concept for how to fix this. Of course I don't understand the inner working of QT or Krita, I'm just an artist, so this is going off of theoretical data and my desire to help.

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 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’.
Comment 3 wolthera 2021-09-09 13:24:17 UTC
There's a new option in the tablet settings in Krita 5.0, which suggests using the driver time stamp instead of a timer based one.

If that doesn't work, I'm afraid we can't do much. The problem isn't so much whether your tablet can sent events, the problem is that the OS compresses them and only sents it to Krita whenever it feels like it. So we can't really do anything here.