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

Jonas Ådahl jadahl at gmail.com
Mon Aug 10 01:21:34 PDT 2015


On Wed, Aug 05, 2015 at 04:32:35PM +1000, Peter Hutterer wrote:
> 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>

Much much more easy to follow now. Most of the reviewing time of this
patch was trying to re-understand and confirm the f1 f2 min max code
did what the new description explains. The new code make that a lot more
obvious.

Reviewed-by: Jonas Ådahl <jadahl at gmail.com>

> ---
>  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
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list