dix: use average of pointer accel profile

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Simon Thum 2008-07-29 10:07:43 +02:00 committed by Peter Hutterer
parent 25882af6d3
commit 18e9fd69fe
3 changed files with 115 additions and 31 deletions

View File

@ -73,7 +73,8 @@ InitFilterChain(DeviceVelocityPtr s, float rdecay, float degression,
void
CleanupFilterChain(DeviceVelocityPtr s);
static float
SimpleSmoothProfile(DeviceVelocityPtr pVel, float threshold, float acc);
SimpleSmoothProfile(DeviceVelocityPtr pVel, float velocity,
float threshold, float acc);
/********************************
@ -88,6 +89,7 @@ InitVelocityData(DeviceVelocityPtr s)
{
s->lrm_time = 0;
s->velocity = 0;
s->last_velocity = 0;
s->corr_mul = 10.0; /* dots per 10 milisecond should be usable */
s->const_acceleration = 1.0; /* no acceleration/deceleration */
s->reset_time = 300;
@ -97,6 +99,7 @@ InitVelocityData(DeviceVelocityPtr s)
s->use_softening = 1;
s->min_acceleration = 1.0; /* don't decelerate */
s->coupling = 0.25;
s->average_accel = TRUE;
s->profile_private = NULL;
memset(&s->statistics, 0, sizeof(s->statistics));
memset(&s->filters, 0, sizeof(s->filters));
@ -163,7 +166,7 @@ InitFilterChain(DeviceVelocityPtr s, float rdecay, float progression, int stages
rdecay /= progression;
}
/* release again. Should the input loop be threaded, we also need
* memory release here (in princliple).
* memory release here (in principle).
*/
OsReleaseSignals();
}
@ -330,10 +333,14 @@ ProcessVelocityData(
float cvelocity;
int diff = time - s->lrm_time;
int cur_ax = GetAxis(dx, dy);
int last_ax = GetAxis(s->last_dx, s->last_dy);
int cur_ax, last_ax;
short reset = (diff >= s->reset_time);
/* remember last round's result */
s->last_velocity = s->velocity;
cur_ax = GetAxis(dx, dy);
last_ax = GetAxis(s->last_dx, s->last_dy);
if(cur_ax != last_ax && cur_ax != -1 && last_ax != -1 && !reset){
/* correct for the error induced when diagonal movements are
reported as alternating axis mickeys */
@ -368,15 +375,22 @@ ProcessVelocityData(
if (diff == 0)
diff = 1; /* prevent div-by-zero, though it shouldn't happen anyway*/
/* translate velocity to dots/ms (somewhat untractable in integers,
/* translate velocity to dots/ms (somewhat intractable in integers,
so we multiply by some per-device adjustable factor) */
cvelocity = cvelocity * s->corr_mul / (float)diff;
/* short-circuit: when nv-reset the rest can be skipped */
if(reset == TRUE){
/*
* we don't really have a velocity here, since diff includes inactive
* time. This is dealt with in ComputeAcceleration.
*/
StuffFilterChain(s, cvelocity);
s->velocity = cvelocity;
s->velocity = s->last_velocity = cvelocity;
s->last_reset = TRUE;
#ifdef PTRACCEL_DEBUGGING
ErrorF("(dix ptracc) non-visible state reset\n");
#endif
return TRUE;
}
@ -388,6 +402,9 @@ ProcessVelocityData(
* stuff that into the filter chain.
*/
s->last_reset = FALSE;
#ifdef PTRACCEL_DEBUGGING
ErrorF("(dix ptracc) after-reset vel:%.3f\n", cvelocity);
#endif
StuffFilterChain(s, cvelocity);
s->velocity = cvelocity;
return FALSE;
@ -448,6 +465,72 @@ ApplySofteningAndConstantDeceleration(
*fdy *= s->const_acceleration;
}
/*
* compute the acceleration for given velocity and enforce min_acceleartion
*/
static float
BasicComputeAcceleration(
DeviceVelocityPtr pVel,
float velocity,
float threshold,
float acc){
float result;
result = pVel->Profile(pVel, velocity, threshold, acc);
/* enforce min_acceleration */
if (result < pVel->min_acceleration)
result = pVel->min_acceleration;
return result;
}
/**
* Compute acceleration. Takes into account averaging, nv-reset, etc.
*/
static float
ComputeAcceleration(
DeviceVelocityPtr vel,
float threshold,
float acc){
float res;
if(vel->last_reset){
#ifdef PTRACCEL_DEBUGGING
ErrorF("(dix ptracc) profile skipped\n");
#endif
/*
* This is intended to override the first estimate of a stroke,
* which is too low (see ProcessVelocityData). 1 should make sure
* the mickey is seen on screen.
*/
return 1;
}
if(vel->average_accel && vel->velocity != vel->last_velocity){
/* use simpson's rule to average acceleration between
* current and previous velocity.
* Though being the more natural choice, it causes a minor delay
* in comparison, so it can be disabled. */
res = BasicComputeAcceleration(vel, vel->velocity, threshold, acc);
res += BasicComputeAcceleration(vel, vel->last_velocity, threshold, acc);
res += 4.0f * BasicComputeAcceleration(vel,
(vel->last_velocity + vel->velocity) / 2,
threshold, acc);
res /= 6.0f;
#ifdef PTRACCEL_DEBUGGING
ErrorF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n",
vel->velocity, vel->last_velocity, res);
#endif
return res;
}else{
res = BasicComputeAcceleration(vel, vel->velocity, threshold, acc);
#ifdef PTRACCEL_DEBUGGING
ErrorF("(dix ptracc) profile sample [%.2f] is %.3f\n",
vel->velocity, res);
#endif
return res;
}
}
/*****************************************
@ -460,10 +543,11 @@ ApplySofteningAndConstantDeceleration(
static float
PolynomialAccelerationProfile(
DeviceVelocityPtr pVel,
float velocity,
float ignored,
float acc)
{
return pow(pVel->velocity, (acc - 1.0) * 0.5);
return pow(velocity, (acc - 1.0) * 0.5);
}
@ -474,15 +558,18 @@ PolynomialAccelerationProfile(
static float
ClassicProfile(
DeviceVelocityPtr pVel,
float velocity,
float threshold,
float acc)
{
if (threshold) {
return SimpleSmoothProfile (pVel,
velocity,
threshold,
acc);
} else {
return PolynomialAccelerationProfile (pVel,
velocity,
0,
acc);
}
@ -500,6 +587,7 @@ ClassicProfile(
static float
PowerProfile(
DeviceVelocityPtr pVel,
float velocity,
float threshold,
float acc)
{
@ -507,9 +595,9 @@ PowerProfile(
acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */
if (pVel->velocity <= threshold)
if (velocity <= threshold)
return pVel->min_acceleration;
vel_dist = pVel->velocity - threshold;
vel_dist = velocity - threshold;
return (pow(acc, vel_dist)) * pVel->min_acceleration;
}
@ -536,10 +624,10 @@ CalcPenumbralGradient(float x){
static float
SimpleSmoothProfile(
DeviceVelocityPtr pVel,
float velocity,
float threshold,
float acc)
{
float velocity = pVel->velocity;
if(velocity < 1.0f)
return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f;
if(threshold < 1.0f)
@ -561,6 +649,7 @@ SimpleSmoothProfile(
static float
SmoothLinearProfile(
DeviceVelocityPtr pVel,
float velocity,
float threshold,
float acc)
{
@ -571,7 +660,7 @@ SmoothLinearProfile(
else
return 1.0f;
nv = (pVel->velocity - threshold) * acc * 0.5f;
nv = (velocity - threshold) * acc * 0.5f;
if(nv < 0){
res = 0;
@ -590,10 +679,11 @@ SmoothLinearProfile(
static float
LinearProfile(
DeviceVelocityPtr pVel,
float velocity,
float threshold,
float acc)
{
return acc * pVel->velocity;
return acc * velocity;
}
@ -730,7 +820,9 @@ acceleratePointerPredictable(
if (dx || dy){
/* reset nonvisible state? */
if (ProcessVelocityData(velocitydata, dx , dy, evtime)) {
/* set to center of pixel */
/* set to center of pixel. makes sense as long as there are no
* means of passing on sub-pixel values.
*/
pDev->last.remainder[0] = pDev->last.remainder[1] = 0.5f;
/* prevent softening (somewhat quirky solution,
as it depends on the algorithm) */
@ -740,22 +832,10 @@ acceleratePointerPredictable(
if (pDev->ptrfeed && pDev->ptrfeed->ctrl.num) {
/* invoke acceleration profile to determine acceleration */
mult = velocitydata->Profile(velocitydata,
pDev->ptrfeed->ctrl.threshold,
(float)pDev->ptrfeed->ctrl.num /
(float)pDev->ptrfeed->ctrl.den);
#ifdef PTRACCEL_DEBUGGING
ErrorF("(dix ptracc) resulting speed multiplier : %.3f\n", mult);
#endif
/* enforce min_acceleration */
if (mult < velocitydata->min_acceleration) {
#ifdef PTRACCEL_DEBUGGING
ErrorF("(dix ptracc) enforced min multiplier : %.3f\n",
velocitydata->min_acceleration);
#endif
mult = velocitydata->min_acceleration;
}
mult = ComputeAcceleration (velocitydata,
pDev->ptrfeed->ctrl.threshold,
(float)pDev->ptrfeed->ctrl.num /
(float)pDev->ptrfeed->ctrl.den);
if(mult != 1.0 || velocitydata->const_acceleration != 1.0) {
ApplySofteningAndConstantDeceleration( velocitydata,

View File

@ -150,6 +150,8 @@ ProcessVelocityConfiguration(char* devname, pointer list, DeviceVelocityPtr s){
s->use_softening = xf86SetBoolOption(list, "Softening",
s->const_acceleration == 1.0);
s->average_accel = xf86SetBoolOption(list, "AccelerationProfileAveraging", TRUE);
s->reset_time = xf86SetIntOption(list, "VelocityReset", 300);
tempf = xf86SetRealOption(list, "ExpectedRate", 0);
@ -214,7 +216,7 @@ ApplyAccelerationSettings(DeviceIntPtr dev){
/* process special configuration */
switch(scheme){
case PtrAccelPredictable:
pVel = (DeviceVelocityPtr) dev->valuator->accelScheme.accelData;
pVel = GetDevicePredictableAccelData(dev);
ProcessVelocityConfiguration (local->name, local->options,
pVel);
break;

View File

@ -53,7 +53,7 @@ struct _DeviceVelocityRec;
*/
typedef float (*PointerAccelerationProfileFunc)
(struct _DeviceVelocityRec* /*pVel*/,
float /*threshold*/, float /*acc*/);
float /*velocity*/, float /*threshold*/, float /*acc*/);
/**
* a filter stage contains the data for adaptive IIR filtering.
@ -78,6 +78,7 @@ typedef struct _FilterStage {
typedef struct _DeviceVelocityRec {
FilterStage filters[MAX_VELOCITY_FILTERS];
float velocity; /* velocity as guessed by algorithm */
float last_velocity; /* previous velocity estimate */
int lrm_time; /* time the last motion event was processed */
int last_dx, last_dy; /* last motion delta */
int last_diff; /* last time-difference */
@ -88,6 +89,7 @@ typedef struct _DeviceVelocityRec {
short reset_time; /* config: reset non-visible state after # ms */
short use_softening; /* config: use softening of mouse values */
float coupling; /* config: max. divergence before coupling */
Bool average_accel; /* config: average acceleration over velocity */
PointerAccelerationProfileFunc Profile;
PointerAccelerationProfileFunc deviceSpecificProfile;
void* profile_private;/* extended data, see SetAccelerationProfile() */