From 18e9fd69fe01298d825b46415b9c6bd86c75dfe5 Mon Sep 17 00:00:00 2001 From: Simon Thum Date: Tue, 29 Jul 2008 10:07:43 +0200 Subject: [PATCH] dix: use average of pointer accel profile Signed-off-by: Peter Hutterer --- dix/ptrveloc.c | 138 ++++++++++++++++++++++++++------- hw/xfree86/common/xf86Xinput.c | 4 +- include/ptrveloc.h | 4 +- 3 files changed, 115 insertions(+), 31 deletions(-) diff --git a/dix/ptrveloc.c b/dix/ptrveloc.c index 21a2eca48..70057e92d 100644 --- a/dix/ptrveloc.c +++ b/dix/ptrveloc.c @@ -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, diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index ea4dbbad2..4ef75301d 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -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; diff --git a/include/ptrveloc.h b/include/ptrveloc.h index 2d42dda29..384f9a6f2 100644 --- a/include/ptrveloc.h +++ b/include/ptrveloc.h @@ -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() */