Opened 3 years ago

Last modified 6 months ago

#136 new defect

Jerky mouse movement when using SDL2 backend on Linux

Reported by: chestertonic@… Owned by: pulkomandy
Priority: major Milestone: 2.9
Component: GrafX2 Version: 2.6
Keywords: Cc:

Description

It only seems to affect the cursor on the canvas as movement over the UI is smooth. It's especially noticeable when using the brush grab tool and also when using the magnifier.
I have a high polling rate mouse and attempted to remedy the effect by increasing the merge movement option by 1 a couple times to no avail. The X11 backend works fine and SDL 1.2 works if I increase merge movement to 2. It's probably a bug in SDL2 but I figured I'd say something anyway.

Change History (6)

comment:1 by PulkoMandy, 3 years ago

Milestone: 2.8

comment:2 by PulkoMandy, 21 months ago

Milestone: 2.82.9

comment:3 by n.bruenggel@…, 6 months ago

Hi there,

I noticed a similar problem on my Mac (macOS 11.6.6 (20G624), SDL 2). The cursor moves fine when using Apple's Magic Mouse 2, but with my Logitech G mouse it becomes super jerky if I set it to higher speed. I believe the problem is because it works at a higher frequency (see this [thread](https://github.com/libsdl-org/SDL/issues/4376) where they recommend to use call SDL_PumpEvents just once per frame.

I do not fully understand how the event loop works (the do .. while loop in Main_handler is pretty big), but from what I read so far I think the problem could be fixed by running it at a fixed frequency (for example 60Hz). To quickly validate this I added some code to measure the number of times SDL_PumpEvents is called per second. I measured it in engine.c, at line 769 where Get_input (which calls SDL_PumpEvents when using SDL 2) is called. It turns out that, when using the Logitech Mouse in fast mode, it is sometimes called almost 300 times per second which seems to cause the jerky movements.

I would be glad if a more experienced developer could comment on this so the bug can eventually be fixed.

comment:4 by PulkoMandy, 6 months ago

As mentionned in the ticket, there is a "merge movement" setting for that in the settings file and it works for the other backends but apparently not for SDL2.

The code is intentionally designed to capture all movements from the mouse as fast as possible, and then process them even if it happens with a bit of delay. This code was written this way for old, slow machines, back when GrafX2 was running for DOS. If you are drawing with a rather large brush or some complex effect, it's expected that the drawing will not happen in realtime.

If you write code in a way that skips mouse events, it will draw faster, sure, but the precision of your mouse gesture (or "brush stroke") will be lost. Instead of a nice curve exactly matching the movement, you will now have several straight line segments between the points that GrafX2 captured. We don't want that.

However, with high resolution mouses, we get a lot more movements than we really need. Especially when working with high zoom factors where really a movement of just a few pixels doesn't really matter. That's what the "merge movement" code is supposed to solve, by allowing to manually tweak this to match your personal setup (your mouse, your OS, your display size and resolution, and the way you use grafx2).

comment:5 by n.bruenggel@…, 6 months ago

I'm not suggesting to drop any events but to limit the number of calls to SDL_PumpEvents to one per frame (at a fixed frame rate). After pumping the events can be retrieved with SDL_PeepEvents.

comment:6 by yrizoud@…, 6 months ago

If I remember correctly, the editor engine has two states:
1) "when you are drawing". This starts when you first click, and only ends when the operation is completed (not necessarily the same mouse button release, some drawing tools involves several clicks.
2) at rest

We wanted to preserve maximum mouse faithfullness during drawing, so while the engine is in state 1, every input event is taken into account, possibly filling the event queue. In state 1, "merge mouse movement" is taken into account, and will skip-ahead 1 mouse movement per loop, or more depending on the setting.

when using the brush grab tool

I had never thought of it before, but the entire "Brush" tool should behave like state 2. Brush stretcher, too. There are many cases where there the last mouse position is the only useful one. We should probably add flags for tools, or event sub-states of tools, where full mouse "trajectory" is not needed

Note: See TracTickets for help on using tickets.