diff options
| author | a1xd <[email protected]> | 2021-03-30 18:27:02 -0400 |
|---|---|---|
| committer | a1xd <[email protected]> | 2021-03-30 18:27:02 -0400 |
| commit | fa3ebfb1eb054ba88824a908c996094bb98e85c5 (patch) | |
| tree | bf52cf6d5de16714dba11e96719ce1434a686779 | |
| parent | put utility in namespace (diff) | |
| download | rawaccel-fa3ebfb1eb054ba88824a908c996094bb98e85c5.tar.xz rawaccel-fa3ebfb1eb054ba88824a908c996094bb98e85c5.zip | |
refactor lut/motivity
| -rw-r--r-- | common/accel-lookup.hpp | 152 | ||||
| -rw-r--r-- | common/accel-motivity.hpp | 114 | ||||
| -rw-r--r-- | common/accel-power.hpp | 1 | ||||
| -rw-r--r-- | common/accel-union.hpp | 81 | ||||
| -rw-r--r-- | common/common.vcxitems | 1 | ||||
| -rw-r--r-- | common/rawaccel-base.hpp | 21 | ||||
| -rw-r--r-- | common/rawaccel-io.hpp | 23 | ||||
| -rw-r--r-- | common/rawaccel.hpp | 11 | ||||
| -rw-r--r-- | common/utility.hpp | 35 | ||||
| -rw-r--r-- | driver/driver.cpp | 41 | ||||
| -rw-r--r-- | driver/driver.h | 1 |
11 files changed, 315 insertions, 166 deletions
diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp new file mode 100644 index 0000000..18c9ea5 --- /dev/null +++ b/common/accel-lookup.hpp @@ -0,0 +1,152 @@ +#pragma once + +#include "rawaccel-base.hpp" +#include "utility.hpp" + +namespace rawaccel { + + struct linear_range { + double start; + double stop; + int num; + + template <typename Func> + void for_each(Func fn) const + { + double interval = (stop - start) / (num - 1); + for (int i = 0; i < num; i++) { + fn(i * interval + start); + } + } + + int size() const + { + return num; + } + }; + + + // represents the range [2^start, 2^stop], with num - 1 + // elements linearly spaced between each exponential step + struct fp_rep_range { + int start; + int stop; + int num; + + template <typename Func> + void for_each(Func fn) const + { + for (int e = 0; e < stop - start; e++) { + double exp_scale = scalbn(1, e + start) / num; + + for (int i = 0; i < num; i++) { + fn((i + num) * exp_scale); + } + } + + fn(scalbn(1, stop)); + } + + int size() const + { + return (stop - start) * num + 1; + } + }; + + template <typename Lookup> + struct lut_base { + enum { capacity = LUT_CAPACITY }; + using value_t = float; + + template <typename Func> + void fill(Func fn) + { + auto* self = static_cast<Lookup*>(this); + + self->range.for_each([&, fn, i = 0](double x) mutable { + self->data[i++] = static_cast<value_t>(fn(x)); + }); + } + + }; + + struct linear_lut : lut_base<linear_lut> { + linear_range range; + bool transfer = false; + value_t data[capacity] = {}; + + double operator()(double x) const + { + if (x > range.start) { + double range_dist = range.stop - range.start; + double idx_f = (x - range.start) * (range.num - 1) / range_dist; + + unsigned idx = min(static_cast<int>(idx_f), range.size() - 2); + + if (idx < capacity - 1) { + double y = lerp(data[idx], data[idx + 1], idx_f - idx); + if (transfer) y /= x; + return y; + } + } + + double y = data[0]; + if (transfer) y /= range.start; + return y; + } + + linear_lut(const table_args& args) : + range({ + args.start, + args.stop, + args.num_elements + }), + transfer(args.transfer) {} + + linear_lut(const accel_args& args) : + linear_lut(args.lut_args) {} + }; + + struct binlog_lut : lut_base<binlog_lut> { + fp_rep_range range; + double x_start; + bool transfer = false; + value_t data[capacity] = {}; + + double operator()(double x) const + { + int e = min(ilogb(x), range.stop - 1); + + if (e >= range.start) { + int idx_int_log_part = e - range.start; + double idx_frac_lin_part = scalbn(x, -e) - 1; + double idx_f = range.num * (idx_int_log_part + idx_frac_lin_part); + + unsigned idx = min(static_cast<int>(idx_f), range.size() - 2); + + if (idx < capacity - 1) { + double y = lerp(data[idx], data[idx + 1], idx_f - idx); + if (transfer) y /= x; + return y; + } + } + + double y = data[0]; + if (transfer) y /= x_start; + return y; + } + + binlog_lut(const table_args& args) : + range({ + static_cast<int>(args.start), + static_cast<int>(args.stop), + args.num_elements + }), + x_start(scalbn(1, range.start)), + transfer(args.transfer) {} + + binlog_lut(const accel_args& args) : + binlog_lut(args.lut_args) {} + }; + +} diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp index a3cb027..0c15598 100644 --- a/common/accel-motivity.hpp +++ b/common/accel-motivity.hpp @@ -1,100 +1,56 @@ #pragma once -#include "rawaccel-base.hpp" +#include "accel-lookup.hpp" #include <math.h> -#define RA_LOOKUP - namespace rawaccel { - constexpr size_t LUT_SIZE = 601; - - struct si_pair { - double slope = 0; - double intercept = 0; - }; - - /// <summary> Struct to hold sigmoid (s-shaped) gain implementation. </summary> - struct motivity { - double rate; - double limit; + struct sigmoid { + double accel; + double motivity; double midpoint; - double subtractive_constant; - - motivity(const accel_args& args) : - rate(pow(10,args.accel_motivity)), - limit(2*log10(args.limit)), - midpoint(log10(args.midpoint)) - { - subtractive_constant = limit / 2; - } + double constant; - double operator()(double speed) const - { - double log_speed = log10(speed); - return pow(10, limit / (exp(-rate * (log_speed - midpoint)) + 1) - subtractive_constant); + sigmoid(const accel_args& args) : + accel(exp(args.accel_motivity)), + motivity(2 * log(args.motivity)), + midpoint(log(args.midpoint)), + constant(-motivity / 2) {} - } - - double apply(si_pair* lookup, double speed) const + double operator()(double x) const { - si_pair pair = lookup[map(speed)]; - return pair.slope + pair.intercept / speed; + double denom = exp(accel * (midpoint - log(x))) + 1; + return exp(motivity / denom + constant); } + }; - int map(double speed) const - { - int index = speed > 0 ? (int)(100 * log10(speed) + 201) : 0; - - if (index < 0) return 0; - if (index >= LUT_SIZE) return LUT_SIZE - 1; + /// <summary> Struct to hold sigmoid (s-shaped) gain implementation. </summary> + struct motivity : binlog_lut { - return index; - } + using binlog_lut::operator(); - void fill(si_pair* lookup) const + motivity(const accel_args& args) : + binlog_lut(args) { - double lookup_speed = 0; - double integral_interval = 0; - double gain_integral_speed = 0; - double gain_integral_speed_prev = 0; - double gain = 0; - double intercept = 0; - double output = 0; - double output_prev = 0; - double x = -2; - - double logarithm_interval = 0.01; - double integral_intervals_per_speed = 10; - double integral_interval_factor = pow(10, logarithm_interval) / integral_intervals_per_speed; - - lookup[0] = {}; - - for (size_t i = 1; i < LUT_SIZE; i++) - { - x += logarithm_interval; - - // Each lookup speed will be 10^0.01 = 2.33% higher than the previous - // To get 10 integral intervals per speed, set interval to 0.233% - lookup_speed = pow(10, x); - integral_interval = lookup_speed * integral_interval_factor; - - while (gain_integral_speed < lookup_speed) - { - output_prev = output; - gain_integral_speed_prev = gain_integral_speed; - gain_integral_speed += integral_interval; - gain = operator()(gain_integral_speed); - output += gain * integral_interval; + double sum = 0; + double a = 0; + auto sigmoid_sum = [&, sig = sigmoid(args)](double b) mutable { + double interval = (b - a) / args.lut_args.partitions; + for (int i = 1; i <= args.lut_args.partitions; i++) { + sum += sig(a + i * interval) * interval; } - - intercept = output_prev - gain_integral_speed_prev * gain; - - lookup[i] = { gain, intercept }; - } - + a = b; + return sum; + }; + + fill([&](double x) { + double y = sigmoid_sum(x); + if (!this->transfer) y /= x; + return y; + }); } + }; } diff --git a/common/accel-power.hpp b/common/accel-power.hpp index c8faabb..a21f926 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -24,4 +24,5 @@ namespace rawaccel { } }; + using power_legacy = power; } diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 97496e1..c63a9cc 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -16,53 +16,59 @@ namespace rawaccel { jump_gain, natural_lgcy, natural_gain, - power, - motivity, + power_lgcy, + power_gain, + motivity_lgcy, + motivity_gain, + lut_log, + lut_lin, noaccel }; - constexpr internal_mode make_mode(accel_mode m, bool legacy) + constexpr internal_mode make_mode(accel_mode mode, table_mode lut_mode, bool legacy) { - switch (m) { - case accel_mode::classic: - return legacy ? internal_mode::classic_lgcy : internal_mode::classic_gain; - case accel_mode::jump: - return legacy ? internal_mode::jump_lgcy : internal_mode::jump_gain; - case accel_mode::natural: - return legacy ? internal_mode::natural_lgcy : internal_mode::natural_gain; - case accel_mode::power: - return internal_mode::power; - case accel_mode::motivity: - return internal_mode::motivity; - default: + if (lut_mode != table_mode::off) { + switch (lut_mode) { + case table_mode::binlog: return internal_mode::lut_log; + case table_mode::linear: return internal_mode::lut_lin; + default: return internal_mode::noaccel; + } + } + else if (mode < accel_mode{} || mode >= accel_mode::noaccel) { return internal_mode::noaccel; } + else { + int im = static_cast<int>(mode) * 2 + (legacy ? 0 : 1); + return static_cast<internal_mode>(im); + } } constexpr internal_mode make_mode(const accel_args& args) { - return make_mode(args.mode, args.legacy); + return make_mode(args.mode, args.lut_args.mode, args.legacy); } template <typename Visitor, typename Variant> inline auto visit_accel(Visitor vis, Variant&& var) { switch (var.tag) { - case internal_mode::classic_lgcy: return vis(var.u.classic_l); - case internal_mode::classic_gain: return vis(var.u.classic_g); - case internal_mode::jump_lgcy: return vis(var.u.jump_l); - case internal_mode::jump_gain: return vis(var.u.jump_g); - case internal_mode::natural_lgcy: return vis(var.u.natural_l); - case internal_mode::natural_gain: return vis(var.u.natural_g); - case internal_mode::power: return vis(var.u.power); - case internal_mode::motivity: return vis(var.u.motivity); - default: return vis(var.u.noaccel); + case internal_mode::classic_lgcy: return vis(var.u.classic_l); + case internal_mode::classic_gain: return vis(var.u.classic_g); + case internal_mode::jump_lgcy: return vis(var.u.jump_l); + case internal_mode::jump_gain: return vis(var.u.jump_g); + case internal_mode::natural_lgcy: return vis(var.u.natural_l); + case internal_mode::natural_gain: return vis(var.u.natural_g); + case internal_mode::power_lgcy: return vis(var.u.power_l); + case internal_mode::power_gain: return vis(var.u.power_g); + case internal_mode::motivity_lgcy: return vis(var.u.motivity_l); + case internal_mode::motivity_gain: return vis(var.u.motivity_g); + case internal_mode::lut_log: return vis(var.u.log_lut); + case internal_mode::lut_lin: return vis(var.u.lin_lut); + default: return vis(var.u.noaccel); } } struct accel_variant { - si_pair* lookup; - internal_mode tag = internal_mode::noaccel; union union_t { @@ -72,30 +78,25 @@ namespace rawaccel { jump_legacy jump_l; natural natural_g; natural_legacy natural_l; - power power; - motivity motivity; + power power_g; + power_legacy power_l; + sigmoid motivity_l; + motivity motivity_g; + linear_lut lin_lut; + binlog_lut log_lut; accel_noaccel noaccel = {}; } u = {}; - accel_variant(const accel_args& args, si_pair* lut = nullptr) : - tag(make_mode(args)), lookup(lut) + accel_variant(const accel_args& args) : + tag(make_mode(args)) { visit_accel([&](auto& impl) { impl = { args }; }, *this); - - if (lookup && tag == internal_mode::motivity) { - u.motivity.fill(lookup); - } - } double apply(double speed) const { - if (lookup && tag == internal_mode::motivity) { - return u.motivity.apply(lookup, speed); - } - return visit_accel([=](auto&& impl) { return impl(speed); }, *this); diff --git a/common/common.vcxitems b/common/common.vcxitems index 6ee47ed..4cbe2b7 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -16,6 +16,7 @@ <ItemGroup> <ClInclude Include="$(MSBuildThisFileDirectory)accel-classic.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)accel-jump.hpp" /> + <ClInclude Include="$(MSBuildThisFileDirectory)accel-lookup.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)accel-motivity.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)accel-natural.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)accel-noaccel.hpp" /> diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index ac60ff0..6996164 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -13,19 +13,38 @@ namespace rawaccel { inline constexpr size_t MAX_DEV_ID_LEN = 200; + inline constexpr size_t LUT_CAPACITY = 1025; + enum class accel_mode { classic, jump, natural, - motivity, power, + motivity, noaccel }; + enum class table_mode { + off, + binlog, + linear + }; + + struct table_args { + table_mode mode = table_mode::off; + bool transfer = true; + unsigned char partitions = 2; + short num_elements = 8; + double start = 0; + double stop = 8; + }; + struct accel_args { accel_mode mode = accel_mode::noaccel; bool legacy = false; + table_args lut_args = {}; + double offset = 0; double cap = 1.5; double accel_classic = 0.005; diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index 0d3ddee..da496fa 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -1,14 +1,15 @@ #pragma once -#include <system_error> +#include "rawaccel-io-def.h" +#include "rawaccel.hpp" +#include "rawaccel-version.h" +#include "rawaccel-error.hpp" #define NOMINMAX +#define WIN32_LEAN_AND_MEAN #include <Windows.h> -#include "rawaccel-io-def.h" -#include "rawaccel-base.hpp" -#include "rawaccel-version.h" -#include "rawaccel-error.hpp" +#include <system_error> #pragma warning(push) #pragma warning(disable:4245) // int -> DWORD conversion while passing CTL_CODE @@ -45,18 +46,14 @@ namespace rawaccel { } } - inline settings read() + inline void read(io_t& args) { - settings args; - io_control(RA_READ, NULL, 0, &args, sizeof(settings)); - return args; + io_control(RA_READ, NULL, 0, &args, sizeof(io_t)); } - - inline void write(const settings& args) + inline void write(const io_t& args) { - auto in_ptr = const_cast<settings*>(&args); - io_control(RA_WRITE, in_ptr, sizeof(settings), NULL, 0); + io_control(RA_WRITE, const_cast<io_t*>(&args), sizeof(io_t), NULL, 0); } inline version_t get_version() diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index f6bc0fd..5d3ee15 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -145,7 +145,7 @@ namespace rawaccel { vec2d sensitivity = { 1, 1 }; vec2d directional_multipliers = {}; - mouse_modifier(const settings& args, vec2<si_pair*> luts = {}) : + mouse_modifier(const settings& args) : by_component(!args.combine_mags), dpi_factor(1000 / args.dpi), speed_cap(args.speed_cap) @@ -172,8 +172,8 @@ namespace rawaccel { return; } - accels.x = accel_variant(args.argsv.x, luts.x); - accels.y = accel_variant(args.argsv.y, luts.y); + accels.x = accel_variant(args.argsv.x); + accels.y = accel_variant(args.argsv.y); distance = weighted_distance(args.dom_args); directional = direction_weight(args.range_weights); @@ -243,4 +243,9 @@ namespace rawaccel { mouse_modifier() = default; }; + struct io_t { + settings args; + mouse_modifier mod; + }; + } // rawaccel diff --git a/common/utility.hpp b/common/utility.hpp index ae14b48..de90d44 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -34,6 +34,33 @@ namespace rawaccel { return minsd(maxsd(v, lo), hi); } + template <typename T> + constexpr const T& min(const T& a, const T& b) + { + return (b < a) ? b : a; + } + + template <typename T> + constexpr const T& max(const T& a, const T& b) + { + return (b < a) ? a : b; + } + + template <typename T> + constexpr const T& clamp(const T& v, const T& lo, const T& hi) + { + return (v < lo) ? lo : (hi < v) ? hi : v; + } + + constexpr double lerp(double a, double b, double t) + { + double x = a + t * (b - a); + if ((t > 1) == (a < b)) { + return maxsd(x, b); + } + return minsd(x, b); + } + // returns the unbiased exponent of x if x is normal inline int ilogb(double x) { @@ -41,6 +68,14 @@ namespace rawaccel { return static_cast<int>((u.i >> 52) & 0x7ff) - 0x3ff; } + // returns x * 2^n if n is in [-1022, 1023] + inline double scalbn(double x, int n) + { + union { double f; unsigned long long i; } u; + u.i = static_cast<unsigned long long>(0x3ff + n) << 52; + return x * u.f; + } + inline bool infnan(double x) { return ilogb(x) == 0x400; diff --git a/driver/driver.cpp b/driver/driver.cpp index 49f375d..89f09dc 100644 --- a/driver/driver.cpp +++ b/driver/driver.cpp @@ -13,13 +13,11 @@ #endif using milliseconds = double; -using lut_value_t = ra::si_pair; struct { ra::settings args; milliseconds tick_interval = 0; // set in DriverEntry ra::mouse_modifier modifier; - vec2<lut_value_t*> lookups = {}; } global = {}; VOID @@ -164,7 +162,7 @@ Return Value: case RA_READ: status = WdfRequestRetrieveOutputBuffer( Request, - sizeof(ra::settings), + sizeof(ra::io_t), &buffer, NULL ); @@ -172,14 +170,18 @@ Return Value: DebugPrint(("RetrieveOutputBuffer failed: 0x%x\n", status)); } else { - *reinterpret_cast<ra::settings*>(buffer) = global.args; - bytes_out = sizeof(ra::settings); + ra::io_t& output = *reinterpret_cast<ra::io_t*>(buffer); + + output.args = global.args; + output.mod = global.modifier; + + bytes_out = sizeof(ra::io_t); } break; case RA_WRITE: status = WdfRequestRetrieveInputBuffer( Request, - sizeof(ra::settings), + sizeof(ra::io_t), &buffer, NULL ); @@ -191,14 +193,10 @@ Return Value: interval.QuadPart = static_cast<LONGLONG>(ra::WRITE_DELAY) * -10000; KeDelayExecutionThread(KernelMode, FALSE, &interval); - ra::settings new_settings = *reinterpret_cast<ra::settings*>(buffer); - - if (new_settings.time_min <= 0 || _isnanf(static_cast<float>(new_settings.time_min))) { - new_settings.time_min = ra::settings{}.time_min; - } + ra::io_t& input = *reinterpret_cast<ra::io_t*>(buffer); - global.args = new_settings; - global.modifier = { global.args, global.lookups }; + global.args = input.args; + global.modifier = input.mod; } break; case RA_GET_VERSION: @@ -276,23 +274,6 @@ Routine Description: KeQueryPerformanceCounter(&freq); global.tick_interval = 1e3 / freq.QuadPart; - auto make_lut = [] { - const size_t POOL_SIZE = sizeof(lut_value_t) * ra::LUT_SIZE; - - auto pool = ExAllocatePoolWithTag(NonPagedPool, POOL_SIZE, 'AR'); - - if (!pool) { - DebugPrint(("RA - failed to allocate LUT\n")); - } - else { - RtlZeroMemory(pool, POOL_SIZE); - } - - return reinterpret_cast<lut_value_t*>(pool); - }; - - global.lookups = { make_lut(), make_lut() }; - CreateControlDevice(driver); } else { diff --git a/driver/driver.h b/driver/driver.h index bb1ae41..56742f6 100644 --- a/driver/driver.h +++ b/driver/driver.h @@ -2,6 +2,7 @@ #include "rawaccel-base.hpp" +#define NOMINMAX #include <ntddk.h> #include <kbdmou.h> #include <wdf.h> |