[PATCH libinput 06/16] filter: explain the acceleration function in detail

Peter Hutterer peter.hutterer at who-t.net
Tue Aug 4 23:32:35 PDT 2015


And switch to a code-flow that's a bit more self-explanatory than the current
min/max combinations.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/filter.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 73 insertions(+), 10 deletions(-)

diff --git a/src/filter.c b/src/filter.c
index b42db35..4f0d8d5 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -421,19 +421,26 @@ pointer_accel_profile_linear_low_dpi(struct motion_filter *filter,
 	struct pointer_accelerator *accel_filter =
 		(struct pointer_accelerator *)filter;
 
-	double f1, f2; /* unitless */
 	double max_accel = accel_filter->accel; /* unitless factor */
-	const double threshold = accel_filter->threshold; /* units/us */
+	double threshold = accel_filter->threshold; /* units/us */
 	const double incline = accel_filter->incline;
 	double factor; /* unitless */
 	double dpi_factor = accel_filter->dpi_factor;
 
+	/* dpi_factor is always < 1.0, increase max_accel, reduce
+	   the threshold so it kicks in earlier */
 	max_accel /= dpi_factor;
+	threshold *= dpi_factor;
 
-	f1 = min(1, 0.3 + v_us2ms(speed_in) * 10.0);
-	f2 = 1 + (v_us2ms(speed_in) - v_us2ms(threshold) * dpi_factor) * incline;
+	/* see pointer_accel_profile_linear for a long description */
+	if (v_us2ms(speed_in) < 0.07)
+		factor = 10 * v_us2ms(speed_in) + 0.3;
+	else if (speed_in < threshold)
+		factor = 1;
+	else
+		factor = incline * v_us2ms(speed_in - threshold) + 1;
 
-	factor = min(max_accel, f2 > 1 ? f2 : f1);
+	factor = min(max_accel, factor);
 
 	return factor;
 }
@@ -446,17 +453,67 @@ pointer_accel_profile_linear(struct motion_filter *filter,
 {
 	struct pointer_accelerator *accel_filter =
 		(struct pointer_accelerator *)filter;
-
-	double f1, f2; /* unitless */
 	const double max_accel = accel_filter->accel; /* unitless factor */
 	const double threshold = accel_filter->threshold; /* units/us */
 	const double incline = accel_filter->incline;
 	double factor; /* unitless */
 
-	f1 = min(1, 0.3 + v_us2ms(speed_in) * 10);
-	f2 = 1 + (v_us2ms(speed_in) - v_us2ms(threshold)) * incline;
+	/*
+	   Our acceleration function calculates a factor to accelerate input
+	   deltas with. The function is a double incline with a plateau,
+	   with a rough shape like this:
 
-	factor = min(max_accel, f2 > 1 ? f2 : f1);
+	  accel
+	 factor
+	   ^
+	   |        /
+	   |  _____/
+	   | /
+	   |/
+	   +-------------> speed in
+
+	   The two inclines are linear functions in the form
+		   y = ax + b
+		   where y is speed_out
+		         x is speed_in
+			 a is the incline of acceleration
+			 b is minimum acceleration factor
+
+	   for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
+	   speed.
+		   hence 1 = a * 0.07 + 0.3
+		       0.3 = a * 0.00 + 0.3 => a := 10
+		   deceleration function is thus:
+			y = 10x + 0.3
+
+	  Note:
+	  * 0.07u/ms as threshold is a result of trial-and-error and
+	    has no other intrinsic meaning.
+	  * 0.3 is chosen simply because it is above the Nyquist frequency
+	    for subpixel motion within a pixel.
+	*/
+	if (v_us2ms(speed_in) < 0.07) {
+		factor = 10 * v_us2ms(speed_in) + 0.3;
+	/* up to the threshold, we keep factor 1, i.e. 1:1 movement */
+	} else if (speed_in < threshold) {
+		factor = 1;
+
+	} else {
+	/* Acceleration function above the threshold:
+		y = ax' + b
+		where T is threshold
+		      x is speed_in
+		      x' is speed
+	        and
+			y(T) == 1
+		hence 1 = ax' + 1
+			=> x' := (x - T)
+	 */
+		factor = incline * v_us2ms(speed_in - threshold) + 1;
+	}
+
+	/* Cap at the maximum acceleration factor */
+	factor = min(max_accel, factor);
 
 	return factor;
 }
@@ -509,6 +566,12 @@ touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
 				  TP_MAGIC_LOW_RES_FACTOR; /* units/us */
 	const double incline = accel_filter->incline * TP_MAGIC_LOW_RES_FACTOR;
 
+	/* Note: the magic values in this function are obtained by
+	 * trial-and-error. No other meaning should be interpreted.
+	 * The calculation is a compressed form of
+	 * pointer_accel_profile_linear(), look at the git history of that
+	 * function for an explaination of what the min/max/etc. does.
+	 */
 	speed_in *= TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
 
 	f1 = min(1, v_us2ms(speed_in) * 5);
-- 
2.4.3



More information about the wayland-devel mailing list