Thursday, May 10, 2018

X server pointer acceleration analysis - part 2

In Part
1 I showed the X server acceleration code as used by the evdev driver
(which leaves all acceleration up to the server). In this part, I'll show
the acceleration code as used by the synaptics touchpad driver. This driver
installs a device-specific acceleration profile but beyond that the
acceleration is... difficult.
The profile itself is not necessarily indicative of the real movement, the
coordinates are scaled between device-relative, device-absolute,
screen-relative, etc. so often that it's hard to keep track of what the real
delta is. So let's look at the profile only.

Diagram generation

Diagrams were generated by gnuplot, parsing .dat files generated by the
ptrveloc tool in the git repo. Helper scripts to regenerate all data
are in the repo too. Default values unless otherwise specified:

MinSpeed: 0.4

MaxSpeed: 0.7

AccelFactor: 0.04

dpi: 1000 (used for converting units to mm)

All diagrams are limited to 100 mm/s and a factor of 5 so they are directly comparable.
From earlier testing I found movements above over 300 mm/s are rare, once you hit 500 mm/s the
acceleration doesn't really matter that much anymore, you're going to hit the screen
edge anyway.

The choice of 1000 dpi is a difficult one. It makes the diagrams directly comparable to those in
Part 1
but touchpads have a great variety in their resolution. For example, an ALPS
DualPoint touchpad may have resolutions of 25-32 units/mm. A Lenovo T440s has a resolution
of 42 units/mm over PS/2 but 20 units/mm over the newer SMBus/RMI4 protocol.
This is the same touchpad. Overall it doesn't actually matter that much though, see below.

The acceleration profile

This driver has a custom acceleration profile, configured by the
MinSpeed, MaxSpeed and AccelFactor options. The former
two put a cap on the factor but MinSpeed also adjusts (overwrites)
ConstantDeceleration. The AccelFactor defaults to a device-specific
size based on the device diagonal.

Let's look at the defaults of 0.4/0.7 for min/max and 0.04 (default on my
touchpad) for the accel factor:

The simple profile from part 1 is shown in this graph for comparison.
The synaptics profile is printed as two curves,
one for the profile output value and one for the real value used on the delta.
Unlike the simple profile you cannot configure ConstantDeceleration separately,
it depends on MinSpeed. Thus the real acceleration factor is always less than
1, so the synaptics driver doesn't accelerate as such, it controls how much the
deltas are decelerated.

The actual acceleration curve is just a plain old linear interpolation between
the min and max acceleration values. If you look at the curves closer you'll
find that there is no acceleration up to 20mm/s and flat acceleration from
25mm/s onwards. Only in this small speed range does the driver adjust its
acceleration based on input speed. Whether this is in intentional or just
happened, I don't know.

The accel factor depends on the touchpad x/y axis. On my T440s using PS/2, the
factor defaults to 0.04. If I get it to use SMBus/RMI4 instead of PS/2, that
same device has an accel factor of 0.09. An ALPS touchpad may have a factor of
0.13, based on the min/max values for the x/y axes. These devices
all have different resolutions though, so here are the comparison graphs
taking the axis range and the resolution into account:

The diagonal affects the accel factor, so these three touchpads (two curves
are the same physical touchpad, just using a different bus) get slightly
different acceleration curves. They're more similar than I expected though
and for the rest of this post we can get away we just looking at the 0.04
default value from my touchpad.

Note that due to how synaptics is handled in the server, this isn't
the whole story, there is more coordinate scaling etc. happening after the
acceleration code. The synaptics acceleration profile also does not
acccommodate for uneven x/y resolutions, this is handled in the server
afterwards. On touchpads with uneven resolutions the velocity thus depends on
the vector, moving along the x axis provides differently sized deltas than
moving along the y axis. However, anything applied later isn't speed dependent
but merely a constant scale, so these curves are still a good representation
of what happens.

The effect of configurations

What does the acceleration factor do? It changes when acceleration kicks in
and how steep the acceleration is.

MinSpeed lifts the baseline (i.e. the minimum acceleration factor), somewhat
expected from a parameter named this way. But it looks again like we have a bug
here. When MinSpeed and MaxSpeed are close together, our acceleration actually
decreases once we're past the threshold. So counterintuitively, a higher
MinSpeed can result in a slower cursor once you move faster.

The same bug is present, if the MaxSpeed is smaller or close to MinSpeed,
our acceleration actually goes down. A quick check of the sources didn't
indicate anything enforcing MinSpeed < MaxSpeed either. But otherwise
MaxSpeed lifts the maximum acceleration factor.

These graphs look at the options in separation, in reality users would
likely configure both MinSpeed and MaxSpeed at the same time. Since both
have an immediate effect on pointer movement, trial and error configuration
is simple and straightforward. Below is a graph of all three adjusted semi-randomly:

No suprises in there, the baseline (and thus slowest speed) changes, the
maximum acceleration changes and how long it takes to get there changes. The curves
vary quite a bit though, so without knowing the configuration options,
it's impossible to predict how a specific touchpad behaves.

Epilogue

The graphs above show the effect of configuration options in the synaptics driver.
I purposely didn't put any specific analysis in and/or compare it to libinput.
That comes in a future post.