From 07c87d1d45af4a3c8111445ab6e6a7863b235d3a Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 4 May 2017 16:37:00 +0200 Subject: compat: add map/filter template functions --- compat/functional.hpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 compat/functional.hpp diff --git a/compat/functional.hpp b/compat/functional.hpp new file mode 100644 index 00000000..e7229d6e --- /dev/null +++ b/compat/functional.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include + +namespace functools +{ + +constexpr void return_void(); + +template +using remove_qualifiers = std::remove_reference_t>; + +template +struct reserver_ +{ + static inline void maybe_reserve_space(seq_&, unsigned) + { + //qDebug() << "nada"; + } +}; + +template +struct reserver_().reserve(0u), return_void())> +{ + static inline void maybe_reserve_space(seq_& seq, unsigned sz) + { + seq.reserve(sz); + } +}; + +template +inline void maybe_reserve_space(seq_& seq, unsigned sz) +{ + reserver_::maybe_reserve_space(seq, sz); +} + +} // ns + +template +auto map(F&& fun, const seq_& seq) +{ + using seq_type = functools::remove_qualifiers; + + seq_type ret; + std::back_insert_iterator it = std::back_inserter(ret); + + for (const auto& elt : seq) + it = fun(elt); + + return ret; +} + +template +auto remove_if_not(F&& fun, const seq_& seq) +{ + using namespace functools; + + using seq_type = remove_qualifiers; + using value_type = typename std::iterator_traits()))>::value_type; + using fun_ret_type = decltype(fun(std::declval())); + static_assert(std::is_convertible::value, "must return bool"); + + seq_type ret; + maybe_reserve_space(ret, seq.size()); + + std::back_insert_iterator it = std::back_inserter(ret); + + for (const value_type& elt : seq) + if (fun(elt)) + it = elt; + + return ret; +} -- cgit v1.2.3 From 6f91be9eec668a2cb27f5065ac86ff1d55f1034b Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 10:36:46 +0200 Subject: options/bundle: skip needless compare-twice --- options/bundle.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/options/bundle.cpp b/options/bundle.cpp index 43f4a8e3..4d44521f 100644 --- a/options/bundle.cpp +++ b/options/bundle.cpp @@ -119,8 +119,7 @@ bool bundle::is_modified() const for (const auto& kv : saved.kvs) { - const QVariant other = transient.get(kv.first); - if (!transient.contains(kv.first) || !is_equal(kv.first, kv.second, other)) + if (!transient.contains(kv.first)) { //if (logspam) // qDebug() << "bundle" << group_name << "modified" << "key" << kv.first << "-" << other << "<>" << kv.second; -- cgit v1.2.3 From a4c33d15687de3bc9222c4f8c7dfea274935c756 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 10:37:47 +0200 Subject: cmake: APPEND_STRING must have a space in front --- cmake/opentrack-boilerplate.cmake | 6 +++--- cmake/opentrack-version.cmake | 2 +- compat/CMakeLists.txt | 2 +- proto-fsuipc/CMakeLists.txt | 2 +- qxt-mini/CMakeLists.txt | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/opentrack-boilerplate.cmake b/cmake/opentrack-boilerplate.cmake index f716ec00..9f6e605b 100644 --- a/cmake/opentrack-boilerplate.cmake +++ b/cmake/opentrack-boilerplate.cmake @@ -75,7 +75,7 @@ endfunction() function(otr_compat target) if(NOT MSVC) - set_property(SOURCE ${${target}-moc} APPEND_STRING PROPERTY COMPILE_FLAGS "-w -Wno-error") + set_property(SOURCE ${${target}-moc} APPEND_STRING PROPERTY COMPILE_FLAGS " -w -Wno-error") endif() if(WIN32) target_link_libraries(${target} dinput8 dxguid strmiids) @@ -95,8 +95,8 @@ function(otr_compat target) set(l-props "-Wl,--as-needed") endif() - set_property(TARGET ${target} APPEND_STRING PROPERTY COMPILE_FLAGS "${c-props} ${arg_COMPILE}") - set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS "${l-props} ${arg_LINK}") + set_property(TARGET ${target} APPEND_STRING PROPERTY COMPILE_FLAGS " ${c-props} ${arg_COMPILE}") + set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${l-props} ${arg_LINK}") endfunction() include(CMakeParseArguments) diff --git a/cmake/opentrack-version.cmake b/cmake/opentrack-version.cmake index 9cd597d3..00a5df1d 100644 --- a/cmake/opentrack-version.cmake +++ b/cmake/opentrack-version.cmake @@ -40,6 +40,6 @@ endif() add_library(opentrack-version STATIC ${CMAKE_BINARY_DIR}/version.c) if(NOT MSVC) - set_property(TARGET opentrack-version APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-lto") + set_property(TARGET opentrack-version APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-lto") endif() otr_compat(opentrack-version) diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index 40850862..7655a223 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -5,5 +5,5 @@ if(NOT WIN32 AND NOT APPLE) endif() if(CMAKE_COMPILER_IS_GNUCXX) - set_property(SOURCE nan.cpp APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-lto -fno-fast-math -fno-finite-math-only -O0") + set_property(SOURCE nan.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-lto -fno-fast-math -fno-finite-math-only -O0") endif() diff --git a/proto-fsuipc/CMakeLists.txt b/proto-fsuipc/CMakeLists.txt index b3e94c32..24006644 100644 --- a/proto-fsuipc/CMakeLists.txt +++ b/proto-fsuipc/CMakeLists.txt @@ -5,7 +5,7 @@ if(WIN32) target_link_libraries(opentrack-proto-fsuipc ${SDK_FSUIPC}/FSUIPC_User.lib) target_include_directories(opentrack-proto-fsuipc SYSTEM PUBLIC ${SDK_FSUIPC}) if(MSVC) - set_property(TARGET opentrack-proto-fsuipc APPEND_STRING PROPERTY LINK_FLAGS "/NODEFAULTLIB:LIBC.lib") + set_property(TARGET opentrack-proto-fsuipc APPEND_STRING PROPERTY LINK_FLAGS " /NODEFAULTLIB:LIBC.lib") endif() endif() endif() diff --git a/qxt-mini/CMakeLists.txt b/qxt-mini/CMakeLists.txt index d09cbdfa..bf8a30f9 100644 --- a/qxt-mini/CMakeLists.txt +++ b/qxt-mini/CMakeLists.txt @@ -3,6 +3,6 @@ if(UNIX OR APPLE) if(NOT APPLE) target_link_libraries(opentrack-qxt-mini X11) else() - set_property(TARGET opentrack-qxt-mini APPEND_STRING PROPERTY LINK_FLAGS "-framework Carbon -framework CoreFoundation") + set_property(TARGET opentrack-qxt-mini APPEND_STRING PROPERTY LINK_FLAGS " -framework Carbon -framework CoreFoundation") endif() endif() -- cgit v1.2.3 From 7d6c570096ae885a24eb525195004fabb2cd7fed Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 10:47:25 +0200 Subject: cmake: unbreak linker language detect for GNU --- cmake/opentrack-boilerplate.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/opentrack-boilerplate.cmake b/cmake/opentrack-boilerplate.cmake index 9f6e605b..7a88e6ef 100644 --- a/cmake/opentrack-boilerplate.cmake +++ b/cmake/opentrack-boilerplate.cmake @@ -84,9 +84,11 @@ function(otr_compat target) set(c-props) set(l-props) + get_property(linker-lang TARGET ${target} PROPERTY LINKER_LANGUAGE) + if(CMAKE_COMPILER_IS_GNUCXX) set(c-props "-fvisibility=hidden") - if(NOT is-c-only) + if(NOT linker-lang STREQUAL "C") set(c-props "${c-props} -fuse-cxa-atexit") endif() endif() -- cgit v1.2.3 From 8faea32f863988c6d55355aaf64f890923a5da5d Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 10:47:40 +0200 Subject: cmake/msvc: add -DHAS_EXCEPTIONS=0 --- cmake/opentrack-platform.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/opentrack-platform.cmake b/cmake/opentrack-platform.cmake index 5bb7581a..3e0319ac 100644 --- a/cmake/opentrack-platform.cmake +++ b/cmake/opentrack-platform.cmake @@ -43,6 +43,7 @@ endif() if(MSVC) add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_ITERATOR_DEBUG_LEVEL=0 -D_HAS_ITERATOR_DEBUGGING=0 -D_SECURE_SCL=0) + add_definitions(-DHAS_EXCEPTIONS=0) set(CMAKE_CXX_FLAGS "-std:c++14 ${CMAKE_CXX_FLAGS}") if(SDK_INSTALL_DEBUG_INFO) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Zi") -- cgit v1.2.3 From 5c3c5a01285245ec046a8203dd7064fad45a02fe Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 10:50:21 +0200 Subject: compat/timer-resolution: don't include windows.h in header --- compat/timer-resolution.cpp | 55 ++++++++++++++++++++++++++------------------- compat/timer-resolution.hpp | 45 ++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 24 deletions(-) diff --git a/compat/timer-resolution.cpp b/compat/timer-resolution.cpp index 597ee91e..d59c250d 100644 --- a/compat/timer-resolution.cpp +++ b/compat/timer-resolution.cpp @@ -8,12 +8,11 @@ #include "timer-resolution.hpp" #if defined _WIN32 -# include - # include # include -typedef LONG (__stdcall *funptr_NtSetTimerResolution) (ULONG, BOOLEAN, PULONG); +using namespace timer_impl; + static funptr_NtSetTimerResolution init_timer_resolution_funptr(); static funptr_NtSetTimerResolution get_funptr(); @@ -41,62 +40,72 @@ static funptr_NtSetTimerResolution init_timer_resolution_funptr() static funptr_NtSetTimerResolution get_funptr() { + // starting with C++11 static initializers are fully + // thread-safe and run the first time function is called + + // cf. http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11 + static auto ret = init_timer_resolution_funptr(); return ret; } -timer_resolution::timer_resolution(int msecs) : old_value(-1) +timer_resolution::timer_resolution(int msecs) : old_value(fail_()) { - if (msecs <= 0 || msecs > 30) + if (msecs <= 0 || msecs > 100) { qDebug() << "can't set timer resolution to" << msecs << "ms"; return; } - funptr_NtSetTimerResolution f = get_funptr(); - if (f == nullptr) + funptr_NtSetTimerResolution set_timer_res = get_funptr(); + if (set_timer_res == nullptr) return; // hundredth of a nanosecond - const ULONG value = msecs * ULONG(10000); - NTSTATUS error = f(value, TRUE, &old_value); - ULONG old_value_ = -1; + const ulong_ value = msecs * ulong_(10000); + ntstatus_ res; - if (error != 0) + res = set_timer_res(value, true_(), &old_value); + + if (res < 0) { - old_value = -1; - qDebug() << "NtSetTimerResolution erred with" << error; + old_value = fail_(); + qDebug() << "NtSetTimerResolution erred with" << res; return; } // see if it stuck - error = f(value, TRUE, &old_value_); - if (error != 0) + ulong_ old_value_ = fail_(); + + res = set_timer_res(value, true_(), &old_value_); + if (res < 0) { - old_value = -1; - qDebug() << "NtSetTimerResolution check erred with" << error; + old_value = fail_(); + qDebug() << "NtSetTimerResolution check erred with" << res; return; } if (old_value_ != old_value) { + using t = long long; + qDebug() << "NtSetTimerResolution:" << "old value didn't stick" - << "current resolution" << old_value_ - << "* 100 ns"; - old_value = -1; + << "current resolution" << (t(old_value_) * t(100)) + << "ns"; + old_value = fail_(); return; } } timer_resolution::~timer_resolution() { - if (old_value != ULONG(-1)) + if (old_value != fail_()) { funptr_NtSetTimerResolution f = get_funptr(); - ULONG fuzz = -1; - (void) f(old_value, TRUE, &fuzz); + ulong_ fuzz = fail_(); + (void) f(old_value, true_(), &fuzz); } } diff --git a/compat/timer-resolution.hpp b/compat/timer-resolution.hpp index 5db877c0..8c18a600 100644 --- a/compat/timer-resolution.hpp +++ b/compat/timer-resolution.hpp @@ -3,14 +3,57 @@ #if defined _WIN32 # include "export.hpp" +#include + +namespace timer_impl +{ + +// cf. https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 +// for NTSTATUS, see http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk + +using ulong_ = unsigned long; +using long_ = long; +using byte_ = unsigned char; +using boolean_ = byte_; + +using true_ = std::integral_constant; + +using fail_ = std::integral_constant; + +// cf. http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk + +// typedef __success(return >= 0) LONG NTSTATUS; + +// __success(expr) T f() : indicates whether function f succeeded or +// not. If is true at exit, all the function's guarantees (as given +// by other annotations) must hold. If is false at exit, the caller +// should not expect any of the function's guarantees to hold. If not used, +// the function must always satisfy its guarantees. Added automatically to +// functions that indicate success in standard ways, such as by returning an +// HRESULT. + +using ntstatus_ = long_; + +// finally what we want +// this is equivalent to typedef syntax + +using funptr_NtSetTimerResolution = ntstatus_ (__stdcall *)(ulong_, boolean_, ulong_*); + +// RAII wrapper + class OTR_COMPAT_EXPORT timer_resolution final { - unsigned long old_value; + ulong_ old_value; public: timer_resolution(int msecs); ~timer_resolution(); }; + +} + +using timer_impl::timer_resolution; + #else struct timer_resolution final { -- cgit v1.2.3 From 604914db84d0468c6c8d04dfe6491e3c15b670f7 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 11:08:29 +0200 Subject: compat/util: more utils --- compat/util.hpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/compat/util.hpp b/compat/util.hpp index b904978b..735fbae6 100644 --- a/compat/util.hpp +++ b/compat/util.hpp @@ -3,6 +3,7 @@ #include "ndebug-guard.hpp" #include "run-in-thread.hpp" #include "meta.hpp" +#include "functional.hpp" #include #include @@ -40,20 +41,34 @@ template using ptr = std::unique_ptr; # define unused_on_unix(t, i) t i #endif +#if defined __GNUC__ +# define likely(x) __builtin_expect((x),1) +# define unlikely(x) __builtin_expect((x),0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif + template -int iround(const t& val) +inline int iround(const t& val) { return int(std::round(val)); } +template +inline unsigned uround(const t& val) +{ + return std::round(std::fmax(t(0), val)); +} + namespace util_detail { template inline auto clamp_(n val, n min, n max) -> n { - if (val > max) + if (unlikely(val > max)) return max; - if (val < min) + if (unlikely(val < min)) return min; return val; } -- cgit v1.2.3 From 87c09c0ab5e1334e9877ee6fd7adeb1eb70d5929 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:15:16 +0200 Subject: options: don't create QSettings all the time Update usages. --- gui/main-window.cpp | 8 ++++ gui/mapping-window.cpp | 11 ++--- logic/mappings.cpp | 6 +-- logic/mappings.hpp | 2 +- migration/20160906_00-mappings.cpp | 40 +++++++--------- migration/migration.cpp | 25 ++++++---- options/CMakeLists.txt | 1 + options/bundle.cpp | 25 +++++----- options/bundle.hpp | 3 +- options/group.cpp | 97 +++++++++++++++++++++++++++----------- options/group.hpp | 35 ++++++++++++-- spline/spline.cpp | 9 +--- spline/spline.hpp | 1 - 13 files changed, 166 insertions(+), 97 deletions(-) diff --git a/gui/main-window.cpp b/gui/main-window.cpp index d64858c4..96be298e 100644 --- a/gui/main-window.cpp +++ b/gui/main-window.cpp @@ -277,6 +277,14 @@ void MainWindow::die_on_config_not_writable() bool MainWindow::maybe_die_on_config_not_writable(const QString& current, QStringList* ini_list_) { + const bool writable = + group::with_settings_object([&](QSettings& s) { + return s.isWritable(); + }); + + if (writable) + return false; + const bool open = QFile(group::ini_combine(current)).open(QFile::ReadWrite); const QStringList ini_list = group::ini_list(); diff --git a/gui/mapping-window.cpp b/gui/mapping-window.cpp index 0ee8c562..0a5d3049 100644 --- a/gui/mapping-window.cpp +++ b/gui/mapping-window.cpp @@ -114,18 +114,15 @@ void MapWidget::closeEvent(QCloseEvent*) void MapWidget::save_dialog() { - mem settings_ = group::ini_file(); - QSettings& settings = *settings_; - - s.b_map->save_deferred(settings); + s.b_map->save(); for (int i = 0; i < 6; i++) { m.forall([&](Map& s) { - s.spline_main.save(settings); - s.spline_alt.save(settings); - s.opts.b_mapping_window->save_deferred(settings); + s.spline_main.save(); + s.spline_alt.save(); + s.opts.b_mapping_window->save(); }); } } diff --git a/logic/mappings.cpp b/logic/mappings.cpp index d7764375..bae8c2c0 100644 --- a/logic/mappings.cpp +++ b/logic/mappings.cpp @@ -11,10 +11,10 @@ Map::Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& op spline_alt.set_max_input(opts.clamp); } -void Map::save(QSettings& s) +void Map::save() { - spline_main.save(s); - spline_alt.save(s); + spline_main.save(); + spline_alt.save(); } void Map::load() diff --git a/logic/mappings.hpp b/logic/mappings.hpp index 4e0f7218..b3587749 100644 --- a/logic/mappings.hpp +++ b/logic/mappings.hpp @@ -17,7 +17,7 @@ struct OTR_LOGIC_EXPORT Map final { Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& opts); - void save(QSettings& s); + void save(); void load(); axis_opts& opts; diff --git a/migration/20160906_00-mappings.cpp b/migration/20160906_00-mappings.cpp index 58674843..a5184825 100644 --- a/migration/20160906_00-mappings.cpp +++ b/migration/20160906_00-mappings.cpp @@ -36,31 +36,30 @@ struct mappings_from_2_3_0_rc11 : migration "rz", "rz_alt", }; - std::shared_ptr settings_ = options::group::ini_file(); - QSettings& settings(*settings_); - - for (const char* name : names) - { - QList points; + return group::with_settings_object([&](QSettings& settings) { + for (const char* name : names) + { + QList points; - settings.beginGroup(QString("Curves-%1").arg(name)); + settings.beginGroup(QString("Curves-%1").arg(name)); - const int max = settings.value("point-count", 0).toInt(); + const int max = settings.value("point-count", 0).toInt(); - for (int i = 0; i < max; i++) - { - QPointF new_point(settings.value(QString("point-%1-x").arg(i), 0).toDouble(), - settings.value(QString("point-%1-y").arg(i), 0).toDouble()); + for (int i = 0; i < max; i++) + { + QPointF new_point(settings.value(QString("point-%1-x").arg(i), 0).toDouble(), + settings.value(QString("point-%1-y").arg(i), 0).toDouble()); - points.append(new_point); - } + points.append(new_point); + } - settings.endGroup(); + settings.endGroup(); - ret.append(points); - } + ret.append(points); + } - return ret; + return ret; + }); } QString unique_date() const override { return "20160909_00"; } @@ -94,9 +93,6 @@ struct mappings_from_2_3_0_rc11 : migration const QList> old_mappings = get_old_splines(); Mappings m = get_new_mappings(); - std::shared_ptr s_ = options::group::ini_file(); - QSettings& s = *s_; - for (int i = 0; i < 12; i++) { spline& spl = (i % 2) == 0 ? m(i / 2).spline_main : m(i / 2).spline_alt; @@ -104,7 +100,7 @@ struct mappings_from_2_3_0_rc11 : migration const QList& points = old_mappings[i]; for (const QPointF& pt : points) spl.add_point(pt); - spl.save(s); + spl.save(); } } }; diff --git a/migration/migration.cpp b/migration/migration.cpp index bb8386fc..747ea06b 100644 --- a/migration/migration.cpp +++ b/migration/migration.cpp @@ -78,11 +78,11 @@ QString migrator::last_migration_time() { QString ret; - std::shared_ptr s(options::group::ini_file()); - - s->beginGroup("migrations"); - ret = s->value("last-migration-at", "19700101_00").toString(); - s->endGroup(); + options::group::with_settings_object([&](QSettings& s) { + s.beginGroup("migrations"); + ret = s.value("last-migration-at", "19700101_00").toString(); + s.endGroup(); + }); return ret; } @@ -102,11 +102,16 @@ QString migrator::time_after_migrations() void migrator::set_last_migration_time(const QString& val) { - std::shared_ptr s(options::group::ini_file()); - - s->beginGroup("migrations"); - s->setValue("last-migration-at", val); - s->endGroup(); + options::group::with_settings_object([&](QSettings& s) { + s.beginGroup("migrations"); + const QString old_value = s.value("last-migration-at", "").toString(); + if (val != old_value) + { + s.setValue("last-migration-at", val); + options::group::mark_ini_modified(); + } + s.endGroup(); + }); } std::vector migrator::sorted_migrations() diff --git a/options/CMakeLists.txt b/options/CMakeLists.txt index cbebeb87..0c4b53a5 100644 --- a/options/CMakeLists.txt +++ b/options/CMakeLists.txt @@ -2,3 +2,4 @@ otr_module(options NO-COMPAT BIN) if(NOT WIN32 AND NOT APPLE) target_link_libraries(opentrack-options rt) endif() +target_link_libraries(opentrack-options opentrack-compat) diff --git a/options/bundle.cpp b/options/bundle.cpp index 4d44521f..c78df274 100644 --- a/options/bundle.cpp +++ b/options/bundle.cpp @@ -31,12 +31,12 @@ bundle::~bundle() { } -void bundle::reload(std::shared_ptr settings) +void bundle::reload() { if (group_name.size()) { QMutexLocker l(&mtx); - saved = group(group_name, settings); + saved = group(group_name); const bool has_changes = is_modified(); transient = saved; @@ -51,7 +51,12 @@ void bundle::reload(std::shared_ptr settings) void bundle::set_all_to_default() { + QMutexLocker l(&mtx); + forall([](const QString&, base_value* val) { set_base_value_to_default(val); }); + + if (is_modified()) + group::mark_ini_modified(); } void bundle::store_kv(const QString& name, const QVariant& datum) @@ -72,10 +77,10 @@ bool bundle::contains(const QString &name) const return transient.contains(name); } -void bundle::save_deferred(QSettings& s) +void bundle::save() { if (QThread::currentThread() != qApp->thread()) - qCritical() << "group::save - current thread not ui thread"; + qDebug() << "group::save - current thread not ui thread"; if (group_name.size() == 0) return; @@ -84,12 +89,13 @@ void bundle::save_deferred(QSettings& s) { QMutexLocker l(&mtx); + if (is_modified()) { //qDebug() << "bundle" << group_name << "changed, saving"; modified_ = true; saved = transient; - saved.save_deferred(s); + saved.save(); } } @@ -97,11 +103,6 @@ void bundle::save_deferred(QSettings& s) emit saving(); } -void bundle::save() -{ - save_deferred(*group::ini_file()); -} - bool bundle::is_modified() const { QMutexLocker l(mtx); @@ -134,8 +135,6 @@ void bundler::after_profile_changed_() { QMutexLocker l(&implsgl_mtx); - std::shared_ptr s = group::ini_file(); - for (auto& kv : implsgl_data) { weak bundle = kv.second; @@ -143,7 +142,7 @@ void bundler::after_profile_changed_() if (bundle_) { //qDebug() << "bundle: reverting" << kv.first << "due to profile change"; - bundle_->reload(s); + bundle_->reload(); } } } diff --git a/options/bundle.hpp b/options/bundle.hpp index f05999a7..63ee82d0 100644 --- a/options/bundle.hpp +++ b/options/bundle.hpp @@ -81,8 +81,7 @@ public: } public slots: void save(); - void reload(std::shared_ptr settings = group::ini_file()); - void save_deferred(QSettings& s); + void reload(); void set_all_to_default(); }; diff --git a/options/group.cpp b/options/group.cpp index 9a4bd912..028e3e48 100644 --- a/options/group.cpp +++ b/options/group.cpp @@ -8,46 +8,47 @@ #include "group.hpp" #include "defs.hpp" + +#include "compat/timer.hpp" + +#include + #include #include - #include namespace options { -group::group(const QString& name, std::shared_ptr conf) : name(name) +group::group(const QString& name) : name(name) { if (name == "") return; - conf->beginGroup(name); - for (auto& k_ : conf->childKeys()) - { - auto tmp = k_.toUtf8(); - QString k(tmp); - kvs[k] = conf->value(k_); - } - conf->endGroup(); -} - -group::group(const QString& name) : group(name, ini_file()) -{ + with_settings_object([&](QSettings& conf) { + conf.beginGroup(name); + for (auto& k_ : conf.childKeys()) + { + auto tmp = k_.toUtf8(); + QString k(tmp); + kvs[k] = conf.value(k_); + } + conf.endGroup(); + }); } void group::save() const -{ - save_deferred(*ini_file()); -} - -void group::save_deferred(QSettings& s) const { if (name == "") return; - s.beginGroup(name); - for (auto& i : kvs) - s.setValue(i.first, i.second); - s.endGroup(); + with_settings_object([&](QSettings& s) { + s.beginGroup(name); + for (auto& i : kvs) + s.setValue(i.first, i.second); + s.endGroup(); + + mark_ini_modified(); + }); } void group::put(const QString &s, const QVariant &d) @@ -103,12 +104,52 @@ QStringList group::ini_list() return list; } -std::shared_ptr group::ini_file() +void group::mark_ini_modified() +{ + QMutexLocker l(&cur_ini_mtx); + ini_modifiedp = true; +} + +QString group::cur_ini_pathname; +std::shared_ptr group::cur_ini; +QMutex group::cur_ini_mtx(QMutex::Recursive); +int group::ini_refcount = 0; +bool group::ini_modifiedp = false; + +std::shared_ptr group::cur_settings_object() { - const auto pathname = ini_pathname(); - if (pathname != "") - return std::make_shared(ini_pathname(), QSettings::IniFormat); - return std::make_shared(); + const QString pathname = ini_pathname(); + + if (pathname.isEmpty()) + return std::make_shared(); + + QMutexLocker l(&cur_ini_mtx); + + if (pathname != cur_ini_pathname) + { + cur_ini = std::make_shared(pathname, QSettings::IniFormat); + cur_ini_pathname = pathname; + } + + return cur_ini; } +group::saver_::~saver_() +{ + if (--ini_refcount == 0 && ini_modifiedp) + { + ini_modifiedp = false; + static Timer t; + const double tm = t.elapsed_seconds(); + qDebug() << QStringLiteral("%1.%2").arg(int(tm)).arg(int(std::fmod(tm, 1.)*10)) + << "saving .ini file" << cur_ini_pathname; + s.sync(); + } } + +group::saver_::saver_(QSettings& s, QMutex& mtx) : s(s), mtx(mtx), lck(&mtx) +{ + ini_refcount++; +} + +} // ns options diff --git a/options/group.hpp b/options/group.hpp index e2a8058c..b0e13a6a 100644 --- a/options/group.hpp +++ b/options/group.hpp @@ -1,13 +1,16 @@ #pragma once #include "export.hpp" + #include "compat/util.hpp" + #include #include #include #include #include #include +#include namespace options { @@ -15,12 +18,27 @@ namespace options { class OTR_OPTIONS_EXPORT group final { QString name; + + static QString cur_ini_pathname; + static std::shared_ptr cur_ini; + static QMutex cur_ini_mtx; + static int ini_refcount; + static bool ini_modifiedp; + struct OTR_OPTIONS_EXPORT saver_ final + { + QSettings& s; + QMutex& mtx; + QMutexLocker lck; + + ~saver_(); + saver_(QSettings& s, QMutex&); + }; + static std::shared_ptr cur_settings_object(); + public: std::map kvs; - group(const QString& name, mem s); group(const QString& name); void save() const; - void save_deferred(QSettings& s) const; void put(const QString& s, const QVariant& d); bool contains(const QString& s) const; static QString ini_directory(); @@ -28,9 +46,11 @@ public: static QString ini_pathname(); static QString ini_combine(const QString& filename); static QStringList ini_list(); - static std::shared_ptr ini_file(); + + static void mark_ini_modified(); template + OTR_NEVER_INLINE t get(const QString& k) const { auto value = kvs.find(k); @@ -38,6 +58,15 @@ public: return value->second.value(); return t(); } + + template + OTR_NEVER_INLINE + static auto with_settings_object(F&& fun) + { + saver_ saver { *cur_settings_object(), cur_ini_mtx }; + + return fun(static_cast(saver.s)); + } }; } diff --git a/spline/spline.cpp b/spline/spline.cpp index 195d68d6..58703e02 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -341,15 +341,10 @@ void spline::reload() s->b->reload(); } -void spline::save(QSettings& settings) -{ - QMutexLocker foo(&_mutex); - s->b->save_deferred(settings); -} - void spline::save() { - save(*group::ini_file()); + QMutexLocker foo(&_mutex); + s->b->save(); } void spline::set_bundle(bundle b) diff --git a/spline/spline.hpp b/spline/spline.hpp index 067967b5..146837c8 100644 --- a/spline/spline.hpp +++ b/spline/spline.hpp @@ -70,7 +70,6 @@ public: using settings = spline_detail::settings; void reload(); - void save(QSettings& s); void save(); void set_bundle(bundle b); -- cgit v1.2.3 From 40058ef9bb1b2beaf2f764e9b6f605e9ff679b77 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:16:06 +0200 Subject: tracker/steamvr: expose all valid devices --- tracker-steamvr/steamvr.cpp | 13 ++++++++++--- tracker-steamvr/steamvr.hpp | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tracker-steamvr/steamvr.cpp b/tracker-steamvr/steamvr.cpp index d32c9d44..43bccdb8 100644 --- a/tracker-steamvr/steamvr.cpp +++ b/tracker-steamvr/steamvr.cpp @@ -55,16 +55,21 @@ void device_list::fill_device_specs(QList& list) device_states, vr::k_unMaxTrackedDeviceCount); static constexpr unsigned bufsiz = vr::k_unTrackingStringSize; - static char str[bufsiz] {}; // vr_lock prevents reentrancy + static char str[bufsiz+1] {}; // vr_lock prevents reentrancy for (unsigned k = 0; k < vr::k_unMaxTrackedDeviceCount; k++) { - if (v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_Invalid || - v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_TrackingReference) + if (v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_Invalid) + { + qDebug() << "no device with index"; continue; + } if (!device_states[k].bDeviceIsConnected) + { + qDebug() << "device not connected but proceeding"; continue; + } unsigned len; @@ -92,6 +97,8 @@ void device_list::fill_device_specs(QList& list) dev.type = "HMD"; break; case vr::ETrackedDeviceClass::TrackedDeviceClass_Controller: dev.type = "Controller"; break; + case vr::ETrackedDeviceClass::TrackedDeviceClass_TrackingReference: + dev.type = "Tracker"; break; default: dev.type = "Unknown"; break; } diff --git a/tracker-steamvr/steamvr.hpp b/tracker-steamvr/steamvr.hpp index e979b9e3..721fded7 100644 --- a/tracker-steamvr/steamvr.hpp +++ b/tracker-steamvr/steamvr.hpp @@ -81,7 +81,7 @@ public: bool center() override; private: - static void matrix_to_euler(double &yaw, double &pitch, double &roll, const vr::HmdMatrix34_t& result); + static void matrix_to_euler(double& yaw, double& pitch, double& roll, const vr::HmdMatrix34_t& result); settings s; int device_index; -- cgit v1.2.3 From 0f634ee3a619b07188975c9fc4f8a0848ec8035b Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:16:55 +0200 Subject: api/plugins: modernize C++ and Qt --- api/plugin-support.hpp | 128 ++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 72 deletions(-) diff --git a/api/plugin-support.hpp b/api/plugin-support.hpp index 2ec55f0e..1bafd6ff 100644 --- a/api/plugin-support.hpp +++ b/api/plugin-support.hpp @@ -8,25 +8,17 @@ #pragma once #include "plugin-api.hpp" -#include "options/options.hpp" -#include +#include +#include + #include #include #include -#include #include - -#include -#include -#include -#include - -#include -#include #include #include -#include +#include #if defined(__APPLE__) # define OPENTRACK_SOLIB_EXT "dylib" @@ -36,27 +28,25 @@ # define OPENTRACK_SOLIB_EXT "so" #endif -#include - #ifdef _MSC_VER # define OPENTRACK_SOLIB_PREFIX "" #else -# define OPENTRACK_SOLIB_PREFIX "" +# define OPENTRACK_SOLIB_PREFIX "lib" #endif extern "C" typedef void* (*OPENTRACK_CTOR_FUNPTR)(void); extern "C" typedef Metadata* (*OPENTRACK_METADATA_FUNPTR)(void); -struct dylib final { - enum Type : unsigned { Filter, Tracker, Protocol, Invalid = 0xcafebabeU }; +struct dylib final +{ + enum Type { Filter = 0xdeadbabe, Tracker = 0xcafebeef, Protocol = 0xdeadf00d, Invalid = 0xcafebabe }; dylib(const QString& filename, Type t) : type(Invalid), filename(filename), Dialog(nullptr), Constructor(nullptr), - Meta(nullptr), - handle(nullptr) + Meta(nullptr) { // otherwise dlopen opens the calling executable if (filename.size() == 0) @@ -77,7 +67,7 @@ struct dylib final { if (check((Meta = (OPENTRACK_METADATA_FUNPTR) handle.resolve("GetMetadata"), !Meta))) return; - auto m = mem(Meta()); + auto m = std::unique_ptr(Meta()); icon = m->icon(); name = m->name(); @@ -94,38 +84,42 @@ struct dylib final { } } - static QList> enum_libraries(const QString& library_path) + static QList> enum_libraries(const QString& library_path) { - const char* filters_n[] = { OPENTRACK_SOLIB_PREFIX "opentrack-filter-*." OPENTRACK_SOLIB_EXT, - OPENTRACK_SOLIB_PREFIX "opentrack-tracker-*." OPENTRACK_SOLIB_EXT, - OPENTRACK_SOLIB_PREFIX "opentrack-proto-*." OPENTRACK_SOLIB_EXT, - }; - const Type filters_t[] = { Filter, Tracker, Protocol }; - - QDir settingsDir(library_path); - - QList> ret; - - for (int i = 0; i < 3; i++) + QDir module_directory(library_path); + QList> ret; + + static const struct filter_ { + Type type; + QString glob; + } filters[] = { + { Filter, OPENTRACK_SOLIB_PREFIX "opentrack-filter-*." OPENTRACK_SOLIB_EXT, }, + { Tracker, OPENTRACK_SOLIB_PREFIX "opentrack-tracker-*." OPENTRACK_SOLIB_EXT, }, + { Protocol, OPENTRACK_SOLIB_PREFIX "opentrack-proto-*." OPENTRACK_SOLIB_EXT, }, + }; + + for (const filter_& filter : filters) { - QString glob = filters_n[i]; - Type t = filters_t[i]; - QStringList filenames = settingsDir.entryList(QStringList { glob }, QDir::Files, QDir::Name); - - for (const QString& filename : filenames) + for (const QString& filename : module_directory.entryList({ filter.glob }, QDir::Files, QDir::Name)) { - QIcon icon; - QString longName; - auto lib = std::make_shared(library_path + filename, t); - if (!get_metadata(lib, longName, icon)) + std::shared_ptr lib = std::make_shared(QStringLiteral("%1/%2").arg(library_path).arg(filename), filter.type); + + if (lib->type == Invalid) + { + qDebug() << "can't load dylib" << filename; continue; + } + if (std::any_of(ret.cbegin(), ret.cend(), - [&](mem a) {return a->type == lib->type && a->name == lib->name;})) + [&lib](const std::shared_ptr& a) { + return a->type == lib->type && a->name == lib->name; + })) { - qDebug() << "Duplicate lib" << lib->filename; + qDebug() << "duplicate lib" << filename << "ident" << lib->name; continue; } + ret.push_back(lib); } } @@ -161,60 +155,50 @@ private: return fail; } - - static bool get_metadata(mem lib, QString& name, QIcon& icon) - { - Metadata* meta; - if (!lib->Meta || ((meta = lib->Meta()), !meta)) - return false; - name = meta->name(); - icon = meta->icon(); - delete meta; - return true; - } }; struct Modules final { + using dylib_ptr = std::shared_ptr; + using dylib_list = QList; + Modules(const QString& library_path) : module_list(dylib::enum_libraries(library_path)), filter_modules(filter(dylib::Filter)), tracker_modules(filter(dylib::Tracker)), protocol_modules(filter(dylib::Protocol)) {} - QList>& filters() { return filter_modules; } - QList>& trackers() { return tracker_modules; } - QList>& protocols() { return protocol_modules; } + dylib_list& filters() { return filter_modules; } + dylib_list& trackers() { return tracker_modules; } + dylib_list& protocols() { return protocol_modules; } private: - QList> module_list; - QList> filter_modules; - QList> tracker_modules; - QList> protocol_modules; + dylib_list module_list; + dylib_list filter_modules; + dylib_list tracker_modules; + dylib_list protocol_modules; - template - static void sort(QList& xs) + static dylib_list& sorted(dylib_list& xs) { - std::sort(xs.begin(), xs.end(), [&](const t& a, const t& b) { return a->name.toLower() < b->name.toLower(); }); + std::sort(xs.begin(), xs.end(), [&](const dylib_ptr& a, const dylib_ptr& b) { return a->name.toLower() < b->name.toLower(); }); + return xs; } - QList> filter(dylib::Type t) + dylib_list filter(dylib::Type t) { - QList> ret; + QList> ret; for (auto x : module_list) if (x->type == t) ret.push_back(x); - sort(ret); - - return ret; + return sorted(ret); } }; template -mem make_dylib_instance(mem lib) +static inline std::shared_ptr make_dylib_instance(const std::shared_ptr& lib) { - mem ret; + std::shared_ptr ret; if (lib != nullptr && lib->Constructor) - ret = mem(reinterpret_cast(reinterpret_cast(lib->Constructor)())); + ret = std::shared_ptr(reinterpret_cast(reinterpret_cast(lib->Constructor)())); return ret; } -- cgit v1.2.3 From 4604742029523e50eacd176c34fee04619c9d809 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:17:04 +0200 Subject: cmake/msvc: -Gm requires -Zi --- cmake/msvc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/msvc.cmake b/cmake/msvc.cmake index bab3f3df..c0aee783 100644 --- a/cmake/msvc.cmake +++ b/cmake/msvc.cmake @@ -43,7 +43,7 @@ if(CMAKE_PROJECT_NAME STREQUAL "opentrack") set(cc "${cc} /GR- /arch:SSE2") endif() -set(silly "${warns_} /MT /Gm") +set(silly "${warns_} -MT -Gm -Zi") set(_CFLAGS "${silly}") set(_CXXFLAGS "${silly}") -- cgit v1.2.3 From 36b6a3b606a36147672c5bf3a3615aaec5486d95 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:17:20 +0200 Subject: cmake: also copy Qt pdb files if they exist --- cmake/opentrack-qt.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/opentrack-qt.cmake b/cmake/opentrack-qt.cmake index d6c8315b..21bc42e1 100644 --- a/cmake/opentrack-qt.cmake +++ b/cmake/opentrack-qt.cmake @@ -6,7 +6,11 @@ set(MY_QT_LIBS ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Widgets_LIBRARIES} if(WIN32) foreach(i Qt5Core Qt5Gui Qt5Network Qt5SerialPort Qt5Widgets) - install(FILES "${Qt5_DIR}/../../../bin/${i}.dll" DESTINATION .) + set(path "${Qt5_DIR}/../../../bin/${i}") + install(FILES "${path}.dll" DESTINATION .) + if(EXISTS "${path}.pdb") + install(FILES "${path}.pdb" DESTINATION "${opentrack-hier-debug}") + endif() endforeach() install(FILES "${Qt5_DIR}/../../../plugins/platforms/qwindows.dll" DESTINATION "./platforms") endif() -- cgit v1.2.3 From 632cd5bf7778cb9062633f8d27ecd6aadcaa5d28 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:18:24 +0200 Subject: filter/accela: punt if running ahead of the input value --- filter-accela/ftnoir_filter_accela.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/filter-accela/ftnoir_filter_accela.cpp b/filter-accela/ftnoir_filter_accela.cpp index 3f78c7a6..b8a0ac77 100644 --- a/filter-accela/ftnoir_filter_accela.cpp +++ b/filter-accela/ftnoir_filter_accela.cpp @@ -32,6 +32,7 @@ static inline constexpr T signum(T x) } template +OTR_NEVER_INLINE static void do_deltas(const double* deltas, double* output, double alpha, double& smoothed, F&& fun) { double norm[N]; @@ -152,6 +153,12 @@ void accela::filter(const double* input, double *output) { output[k] *= dt; output[k] += last_output[k]; + + if (signum(last_output[k] - output[k]) < 0) + output[k] = std::fmax(input[k], output[k]); + else + output[k] = std::fmin(input[k], output[k]); + last_output[k] = output[k]; } } -- cgit v1.2.3 From 03c5a15199b34b564314ac222d51ab687fc97a93 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:23:44 +0200 Subject: get rid of the silly mem -> shared_ptr alias --- gui/main-window.cpp | 8 ++++---- gui/main-window.hpp | 8 ++++---- gui/main.cpp | 4 ++-- logic/selected-libraries.hpp | 11 +++++++---- logic/state.hpp | 2 +- logic/work.cpp | 2 +- logic/work.hpp | 2 +- spline/spline-widget.cpp | 2 +- spline/spline.cpp | 4 ++-- spline/spline.hpp | 6 +++--- 10 files changed, 26 insertions(+), 23 deletions(-) diff --git a/gui/main-window.cpp b/gui/main-window.cpp index 96be298e..aa8e16f3 100644 --- a/gui/main-window.cpp +++ b/gui/main-window.cpp @@ -74,13 +74,13 @@ MainWindow::MainWindow() : { modules.filters().push_front(std::make_shared("", dylib::Filter)); - for (mem& x : modules.trackers()) + for (std::shared_ptr& x : modules.trackers()) ui.iconcomboTrackerSource->addItem(x->icon, x->name); - for (mem& x : modules.protocols()) + for (std::shared_ptr& x : modules.protocols()) ui.iconcomboProtocol->addItem(x->icon, x->name); - for (mem& x : modules.filters()) + for (std::shared_ptr& x : modules.filters()) ui.iconcomboFilter->addItem(x->icon, x->name); } @@ -601,7 +601,7 @@ inline bool MainWindow::mk_window(ptr& place, Args&&... params) } template -bool MainWindow::mk_dialog(mem lib, ptr& d) +bool MainWindow::mk_dialog(std::shared_ptr lib, ptr& d) { const bool just_created = mk_window_common(d, [&]() -> t* { if (lib && lib->Dialog) diff --git a/gui/main-window.hpp b/gui/main-window.hpp index 71e372f0..ef6143e7 100644 --- a/gui/main-window.hpp +++ b/gui/main-window.hpp @@ -68,15 +68,15 @@ class MainWindow : public QMainWindow, private State menu_action_tracker, menu_action_filter, menu_action_proto, menu_action_options, menu_action_mappings; - mem current_tracker() + std::shared_ptr current_tracker() { return modules.trackers().value(ui.iconcomboTrackerSource->currentIndex(), nullptr); } - mem current_protocol() + std::shared_ptr current_protocol() { return modules.protocols().value(ui.iconcomboProtocol->currentIndex(), nullptr); } - mem current_filter() + std::shared_ptr current_filter() { return modules.filters().value(ui.iconcomboFilter->currentIndex(), nullptr); } @@ -99,7 +99,7 @@ class MainWindow : public QMainWindow, private State // only use in impl file since no definition in header! template - bool mk_dialog(mem lib, ptr& d); + bool mk_dialog(std::shared_ptr lib, ptr& d); // idem template diff --git a/gui/main.cpp b/gui/main.cpp index 80040732..16e08b6e 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -129,13 +129,13 @@ main(int argc, char** argv) if (!QSettings(OPENTRACK_ORG).value("disable-translation", false).toBool()) { - (void) t.load(QLocale(), "", "", QCoreApplication::applicationDirPath() + "/" + OPENTRACK_I18N_PATH, ".qm"); + (void) t.load(QLocale(), "", "", QCoreApplication::applicationDirPath() + "/" OPENTRACK_I18N_PATH, ".qm"); (void) QCoreApplication::installTranslator(&t); } do { - mem w = std::make_shared(); + std::shared_ptr w = std::make_shared(); if (!w->isEnabled()) break; diff --git a/logic/selected-libraries.hpp b/logic/selected-libraries.hpp index 689cbec3..65e9733e 100644 --- a/logic/selected-libraries.hpp +++ b/logic/selected-libraries.hpp @@ -15,11 +15,14 @@ struct OTR_LOGIC_EXPORT SelectedLibraries { - using dylibptr = mem; - mem pTracker; - mem pFilter; - mem pProtocol; + using dylibptr = std::shared_ptr; + + std::shared_ptr pTracker; + std::shared_ptr pFilter; + std::shared_ptr pProtocol; + SelectedLibraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f); SelectedLibraries() : pTracker(nullptr), pFilter(nullptr), pProtocol(nullptr), correct(false) {} + bool correct; }; diff --git a/logic/state.hpp b/logic/state.hpp index f5892557..8bef71ad 100644 --- a/logic/state.hpp +++ b/logic/state.hpp @@ -26,5 +26,5 @@ struct State Modules modules; main_settings s; Mappings pose; - mem work; + std::shared_ptr work; }; diff --git a/logic/work.cpp b/logic/work.cpp index 7b9e550e..6829e62b 100644 --- a/logic/work.cpp +++ b/logic/work.cpp @@ -60,7 +60,7 @@ std::shared_ptr Work::make_logger(main_settings &s) } -Work::Work(Mappings& m, QFrame* frame, mem tracker_, mem filter_, mem proto_) : +Work::Work(Mappings& m, QFrame* frame, std::shared_ptr tracker_, std::shared_ptr filter_, std::shared_ptr proto_) : libs(frame, tracker_, filter_, proto_), logger(make_logger(s)), tracker(std::make_shared(m, libs, *logger)), diff --git a/logic/work.hpp b/logic/work.hpp index f1d5e401..dc32536c 100644 --- a/logic/work.hpp +++ b/logic/work.hpp @@ -35,7 +35,7 @@ struct OTR_LOGIC_EXPORT Work std::shared_ptr sc; std::vector keys; - Work(Mappings& m, QFrame* frame, mem tracker, mem filter, mem proto); + Work(Mappings& m, QFrame* frame, std::shared_ptr tracker, std::shared_ptr filter, std::shared_ptr proto); ~Work(); void reload_shortcuts(); bool is_ok() const; diff --git a/spline/spline-widget.cpp b/spline/spline-widget.cpp index fef03e82..c71626f0 100644 --- a/spline/spline-widget.cpp +++ b/spline/spline-widget.cpp @@ -59,7 +59,7 @@ void spline_widget::setConfig(spline* spl) if (spl) { - mem s = spl->get_settings(); + std::shared_ptr s = spl->get_settings(); connection = connect(s.get(), &spline::settings::recomputed, this, [this]() { reload_spline(); }, Qt::QueuedConnection); diff --git a/spline/spline.cpp b/spline/spline.cpp index 58703e02..c1f09db8 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -428,13 +428,13 @@ void spline::recompute() } // the return value is only safe to use with no spline::set_bundle calls -mem spline::get_settings() +std::shared_ptr spline::get_settings() { QMutexLocker foo(&_mutex); return s; } -mem spline::get_settings() const +std::shared_ptr spline::get_settings() const { QMutexLocker foo(&_mutex); return s; diff --git a/spline/spline.hpp b/spline/spline.hpp index 146837c8..acb1861a 100644 --- a/spline/spline.hpp +++ b/spline/spline.hpp @@ -52,7 +52,7 @@ class OTR_SPLINE_EXPORT spline final static QPointF ensure_in_bounds(const QList& points, double max_x, int i); static int element_count(const QList& points, double max_x); - mem s; + std::shared_ptr s; QMetaObject::Connection connection; std::vector data; @@ -99,8 +99,8 @@ public: bundle get_bundle(); void recompute(); - mem get_settings(); - mem get_settings() const; + std::shared_ptr get_settings(); + std::shared_ptr get_settings() const; using points_t = decltype(s->points()); int get_point_count() const; -- cgit v1.2.3 From dd83dc780bd1232444b6051aff5698f63cd4d741 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:25:07 +0200 Subject: filter/ewma: fix labels - single step is a round value now - use a `tie_setting' overload for formatting the value, rather than a separate slot --- filter-ewma2/ftnoir_ewma_filtercontrols.ui | 18 +++++++++--------- filter-ewma2/ftnoir_filter_ewma2.h | 2 -- filter-ewma2/ftnoir_filter_ewma2_dialog.cpp | 26 ++++++++++++++------------ 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/filter-ewma2/ftnoir_ewma_filtercontrols.ui b/filter-ewma2/ftnoir_ewma_filtercontrols.ui index d5cc082e..e0a98174 100644 --- a/filter-ewma2/ftnoir_ewma_filtercontrols.ui +++ b/filter-ewma2/ftnoir_ewma_filtercontrols.ui @@ -23,7 +23,7 @@ EWMA filter settings - + :/images/filter-16.png:/images/filter-16.png @@ -73,7 +73,7 @@ 0 - 1000 + 990 5 @@ -82,7 +82,7 @@ 50 - 1000 + 990 Qt::Horizontal @@ -123,10 +123,10 @@ - 1 + 0 - 1000 + 990 5 @@ -135,7 +135,7 @@ 50 - 1000 + 980 Qt::Horizontal @@ -173,7 +173,7 @@ 0 - 1000 + 2450 5 @@ -182,7 +182,7 @@ 50 - 1000 + 490 Qt::Horizontal @@ -287,7 +287,7 @@ p, li { white-space: pre-wrap; } - + diff --git a/filter-ewma2/ftnoir_filter_ewma2.h b/filter-ewma2/ftnoir_filter_ewma2.h index 8babc540..f8c77280 100644 --- a/filter-ewma2/ftnoir_filter_ewma2.h +++ b/filter-ewma2/ftnoir_filter_ewma2.h @@ -19,7 +19,6 @@ struct settings : opts { {} }; - class ewma : public IFilter { public: @@ -54,7 +53,6 @@ private: private slots: void doOK(); void doCancel(); - void update_labels(int); }; class ewmaDll : public Metadata diff --git a/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp index ad07737b..55e9782e 100644 --- a/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp +++ b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp @@ -1,7 +1,10 @@ #include "ftnoir_filter_ewma2.h" + #include + #include #include + #include "api/plugin-api.hpp" #include "ui_ftnoir_ewma_filtercontrols.h" @@ -16,17 +19,23 @@ dialog_ewma::dialog_ewma() tie_setting(s.kMinSmoothing, ui.minSmooth); tie_setting(s.kSmoothingScaleCurve, ui.powCurve); - connect(ui.powCurve, &QSlider::valueChanged, this, &dialog_ewma::update_labels); - connect(ui.minSmooth, &QSlider::valueChanged, this, &dialog_ewma::update_labels); - connect(ui.maxSmooth, &QSlider::valueChanged, this, &dialog_ewma::update_labels); + tie_setting(s.kSmoothingScaleCurve, ui.curve_label, + [](auto& x) { return x * 100; }, + "%1%", 0, 'f', 2); + + tie_setting(s.kMinSmoothing, ui.min_label, + [](auto& x) { return x * 100; }, + "%1%", 0, 'f', 2); + + tie_setting(s.kMaxSmoothing, ui.max_label, + [](auto& x) { return x * 100; }, + "%1%", 0, 'f', 2); connect(ui.minSmooth, &QSlider::valueChanged, this, [&](int v) -> void { if (ui.maxSmooth->value() < v) ui.maxSmooth->setValue(v); }); connect(ui.maxSmooth, &QSlider::valueChanged, this, [&](int v) -> void { if (ui.minSmooth->value() > v) ui.minSmooth->setValue(v); }); - - update_labels(0); } void dialog_ewma::doOK() @@ -39,10 +48,3 @@ void dialog_ewma::doCancel() { close(); } - -void dialog_ewma::update_labels(int) -{ - ui.curve_label->setText(QString::number(static_cast(s.kSmoothingScaleCurve).cur() * 100, 'f', 2) + "%"); - ui.min_label->setText(QString::number(static_cast(s.kMinSmoothing).cur() * 100, 'f', 2) + "%"); - ui.max_label->setText(QString::number(static_cast(s.kMaxSmoothing).cur() * 100, 'f', 2) + "%"); -} -- cgit v1.2.3 From 33580cee78020e8389834ea271556320f33521e4 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:26:02 +0200 Subject: options/tie: allow for custom-formatting the ini value --- options/tie.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/options/tie.hpp b/options/tie.hpp index a3b5a19f..94fe5d49 100644 --- a/options/tie.hpp +++ b/options/tie.hpp @@ -58,6 +58,23 @@ void tie_setting(value& v, QLabel* lb, const QString& format, const xs&... ar v.SAFE_CONNTYPE); } +// Clang 3.9 has a bug +// error: missing default argument on parameter 'args' + +// cf. http://stackoverflow.com/questions/29098835/can-parameter-pack-function-arguments-be-defaulted + +template +decltype((void)((std::declval())(std::declval()))) +tie_setting(value& v, QLabel* lb, F&& fun, const QString& fmt = QStringLiteral("%1"), const xs&... args) +{ + auto closure = [=](const t& x) { lb->setText(fmt.arg(fun(x), args...)); }; + + closure(v()); + base_value::connect(&v, static_cast(&base_value::valueChanged), + lb, closure, + v.SAFE_CONNTYPE); +} + OTR_OPTIONS_EXPORT void tie_setting(value& v, QComboBox* cb); OTR_OPTIONS_EXPORT void tie_setting(value& v, QComboBox* cb); OTR_OPTIONS_EXPORT void tie_setting(value& v, QComboBox* cb); -- cgit v1.2.3 From ba038ce052af5ada52a0117c9f13e44cf1c63f1c Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:34:22 +0200 Subject: spline: refactor Generally nothing of importance, just readability. - There was a particularly scary typo where: const unsigned end = std::min(unsigned(value_count), unsigned(p2_x * mult_)); clamping to value_count doesn't make sense, given arbitrary p2_x. - Try harder to avoid assigning s->points. Also the overlap threshold constant was arbitrarily too high. - Sort predicate is meant to use strict ordering, not partial total order. --- spline/spline.cpp | 72 +++++++++++++++++++++++++++---------------------------- spline/spline.hpp | 2 +- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/spline/spline.cpp b/spline/spline.cpp index c1f09db8..277ab407 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -113,7 +113,7 @@ float spline::get_value_no_save_internal(double x) if (max_x > 0) x = std::fmin(max_x, x); - float q = float(x * precision(s->points)); + float q = float(x * bucket_size_coefficient(s->points)); int xi = (int)q; float yi = get_value_internal(xi); float yiplus1 = get_value_internal(xi+1); @@ -139,8 +139,7 @@ float spline::get_value_internal(int x) float sign = x < 0 ? -1 : 1; x = std::abs(x); - float ret; - ret = data[std::min(unsigned(x), unsigned(value_count)-1u)]; + float ret = data[std::min(unsigned(x), unsigned(value_count)-1u)]; return ret * sign; } @@ -183,7 +182,7 @@ int spline::element_count(const QList& points, double max_x) bool spline::sort_fn(const QPointF& one, const QPointF& two) { - return one.x() <= two.x(); + return one.x() < two.x(); } void spline::update_interp_data() @@ -197,11 +196,11 @@ void spline::update_interp_data() std::stable_sort(points.begin(), points.begin() + sz, sort_fn); - const double mult = precision(points); - const double mult_ = mult * 30; + const double c = bucket_size_coefficient(points); + const double c_interp = c * 30; for (unsigned i = 0; i < value_count; i++) - data[i] = -1; + data[i] = -16; if (sz < 2) { @@ -209,7 +208,7 @@ void spline::update_interp_data() { const double x = points[0].x(); const double y = points[0].y(); - const int max = clamp(int(x * precision(points)), 1, value_count-1); + const int max = clamp(iround(x * c), 1, value_count-1); for (int k = 0; k <= max; k++) { if (k < value_count) @@ -247,20 +246,21 @@ void spline::update_interp_data() }; // multiplier helps fill in all the x's needed - const unsigned end = std::min(unsigned(value_count), unsigned(p2_x * mult_)); - const unsigned start = std::max(0u, unsigned(p1_x * mult)); + const unsigned end = int(c_interp * (p2_x - p1_x)) + 1; - for (unsigned j = start; j < end; j++) + for (unsigned k = 0; k <= end; k++) { - const double t = (j - start) / (double) (end - start); + const double t = k / double(end); const double t2 = t*t; const double t3 = t*t*t; - const int x = iround(.5 * mult * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3)); + const int x = int(.5 * c * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3)); const float y = float(.5 * (cy[0] + cy[1] * t + cy[2] * t2 + cy[3] * t3)); if (x >= 0 && x < value_count) - data[unsigned(x)] = y; + { + data[x] = y; + } } } } @@ -268,7 +268,7 @@ void spline::update_interp_data() float last = 0; for (unsigned i = 0; i < unsigned(value_count); i++) { - if (data[i] < 0) + if (data[i] == -16) data[i] = last; last = data[i]; } @@ -317,7 +317,7 @@ void spline::move_point(int idx, QPointF pt) { points[idx] = pt; // we don't allow points to be reordered, but sort due to possible caller logic error - //std::stable_sort(points.begin(), points.end(), sort_fn); + std::stable_sort(points.begin(), points.end(), sort_fn); s->points = points; validp = false; } @@ -332,7 +332,7 @@ QList spline::get_points() const int spline::get_point_count() const { QMutexLocker foo(&_mutex); - return element_count(s->points, max_x);; + return element_count(s->points, max_x); } void spline::reload() @@ -389,12 +389,9 @@ void spline::recompute() QList list = s->points; // storing to s->points fires bundle::changed and that leads to an infinite loop - // only store if we can't help it + // thus, only store if we can't help it std::stable_sort(list.begin(), list.end(), sort_fn); - if (list != s->points) - s->points = list; - const int sz = list.size(); QList ret_list; @@ -405,16 +402,16 @@ void spline::recompute() QPointF& pt(list[i]); const bool overlap = progn( - for (int j = 0; j < i; j++) - { - QPointF& pt2(list[j]); - const double dist_sq = (pt.x() - pt2.x())*(pt.x() - pt2.x()); - static constexpr double overlap = .6; - if (dist_sq < overlap * overlap) - return true; - } - return false; - ); + for (int j = 0; j < i; j++) + { + const QPointF& pt2(list[j]); + const double dist_sq = QPointF::dotProduct(pt, pt2); + const double overlap = max_x / 360.; + if (dist_sq < overlap * overlap) + return true; + } + return false; + ); if (!overlap) ret_list.push_back(pt); } @@ -440,14 +437,17 @@ std::shared_ptr spline::get_settings() const return s; } -double spline::precision(const QList& points) const +double spline::bucket_size_coefficient(const QList& points) const { - // this adjusts the memoized range to the largest X value. empty space doesn't take value_count discrete points. + static constexpr double eps = 1e-4; + + if (unlikely(max_x < eps)) + return 0; + const int sz = element_count(points, max_x); - if (sz) - return clamp(value_count / clamp(points[sz - 1].x(), 1., max_x), 0., double(value_count)); + const double last_x = sz ? points[sz - 1].x() : max_x; - return value_count / clamp(max_x, 1., double(value_count)); + return clamp((value_count-1) / clamp(last_x, eps, max_x), 0., (value_count-1)); } namespace spline_detail { diff --git a/spline/spline.hpp b/spline/spline.hpp index acb1861a..7098f125 100644 --- a/spline/spline.hpp +++ b/spline/spline.hpp @@ -42,7 +42,7 @@ signals: class OTR_SPLINE_EXPORT spline final { - double precision(const QList& points) const; + double bucket_size_coefficient(const QList& points) const; void update_interp_data(); float get_value_internal(int x); void add_lone_point(); -- cgit v1.2.3 From e7cdb5b6a0e0152297369d57774caae307e1be77 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 6 May 2017 13:34:41 +0200 Subject: tracker/test: add a quick way to crash the application Don't leave home without it. --- tracker-test/test.cpp | 6 +++++- tracker-test/test.ui | 25 ++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/tracker-test/test.cpp b/tracker-test/test.cpp index 06a4f1f2..c0bc4ef3 100644 --- a/tracker-test/test.cpp +++ b/tracker-test/test.cpp @@ -8,8 +8,10 @@ #include "test.h" #include "api/plugin-api.hpp" -#include +#include + +#include #include const double test_tracker::incr[6] = @@ -79,6 +81,8 @@ test_dialog::test_dialog() { ui.setupUi(this); + connect(ui.buttonBox->button(QDialogButtonBox::Abort), &QPushButton::clicked, []() { *(volatile int*)0 = 0; }); + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); } diff --git a/tracker-test/test.ui b/tracker-test/test.ui index 1141d584..556b19a3 100644 --- a/tracker-test/test.ui +++ b/tracker-test/test.ui @@ -9,8 +9,8 @@ 0 0 - 184 - 39 + 278 + 58 @@ -27,10 +27,29 @@ false + + + + + 0 + 0 + + + + Pressing "Abort" will immediately crash the application. + + + + + + 0 + 0 + + - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::Abort|QDialogButtonBox::Close -- cgit v1.2.3 From e07bde4423eee88d9f9a02b179480de3129d9c93 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 08:08:38 +0200 Subject: options/group: nicely format debug timestamp --- options/group.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/group.cpp b/options/group.cpp index 028e3e48..3f800ff0 100644 --- a/options/group.cpp +++ b/options/group.cpp @@ -141,7 +141,7 @@ group::saver_::~saver_() ini_modifiedp = false; static Timer t; const double tm = t.elapsed_seconds(); - qDebug() << QStringLiteral("%1.%2").arg(int(tm)).arg(int(std::fmod(tm, 1.)*10)) + qDebug() << QStringLiteral("%1.%2").arg(int(tm)).arg(int(std::fmod(tm, 1.)*10)).toLatin1().data() << "saving .ini file" << cur_ini_pathname; s.sync(); } -- cgit v1.2.3 From ebc24a6ab8bbf25620b2f524e94106e9f50cc86d Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 08:08:53 +0200 Subject: proto/evdev: that didn't make sense --- proto-libevdev/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto-libevdev/CMakeLists.txt b/proto-libevdev/CMakeLists.txt index f2809c93..04f6924e 100644 --- a/proto-libevdev/CMakeLists.txt +++ b/proto-libevdev/CMakeLists.txt @@ -5,6 +5,6 @@ if(LINUX OR APPLE) otr_module(proto-libevdev) pkg_check_modules(libevdev REQUIRED QUIET libevdev) target_link_libraries(opentrack-proto-libevdev ${libevdev_LIBRARIES}) - include_directories(opentrack-proto-libevdev SYSTEM PUBLIC ${libevdev_INCLUDE_DIRS}) + target_include_directories(opentrack-proto-libevdev SYSTEM PUBLIC ${libevdev_INCLUDE_DIRS}) endif() endif() -- cgit v1.2.3 From 6ccd173d52f639bf95d82760fb9c3c1943b660d1 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 08:09:39 +0200 Subject: spline: fix points deleting themselves on dragging to origin --- spline/spline.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spline/spline.cpp b/spline/spline.cpp index 277ab407..3787e0f9 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -405,8 +405,9 @@ void spline::recompute() for (int j = 0; j < i; j++) { const QPointF& pt2(list[j]); - const double dist_sq = QPointF::dotProduct(pt, pt2); - const double overlap = max_x / 360.; + const QPointF tmp(pt - pt2); + const double dist_sq = QPointF::dotProduct(tmp, tmp); + const double overlap = max_x / 500.; if (dist_sq < overlap * overlap) return true; } -- cgit v1.2.3 From e8f83186825966232900cf7c70ac88134cbdf0cd Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 08:10:03 +0200 Subject: pose-widget: projected pixel overflow isn'n an issue --- pose-widget/pose-widget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pose-widget/pose-widget.cpp b/pose-widget/pose-widget.cpp index b511f4c5..c3e87dff 100644 --- a/pose-widget/pose-widget.cpp +++ b/pose-widget/pose-widget.cpp @@ -270,8 +270,8 @@ void pose_transform::project_quad_texture() return; } - for (int y = 1; y < sy; y++) - for (int x = 1; x < sx; x++) + for (int y = 0; y < sy; y++) + for (int x = 0; x < sx; x++) { vec2 pos(x, y); vec2 uv; -- cgit v1.2.3 From 940ae0898c5e836c3d82fac85f5fa55bb75414a1 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 08:10:32 +0200 Subject: spline: reformat --- spline/spline.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/spline/spline.cpp b/spline/spline.cpp index 3787e0f9..6167de0d 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -363,17 +363,18 @@ void spline::set_bundle(bundle b) if (b) { connection = QObject::connect(b.get(), &bundle_::changed, - s.get(), [&]() { - // we're holding the mutex to allow signal disconnection in spline dtor - // before this slot gets called for the next time + s.get(), [&]() + { + // we're holding the mutex to allow signal disconnection in spline dtor + // before this slot gets called for the next time - // spline isn't a QObject and the connection context is incorrect + // spline isn't a QObject and the connection context is incorrect - QMutexLocker l(&_mutex); - recompute(); - emit s->recomputed(); - }, - Qt::QueuedConnection); + QMutexLocker l(&_mutex); + recompute(); + emit s->recomputed(); + }, + Qt::QueuedConnection); } recompute(); -- cgit v1.2.3 From d561e59cacc4e22cb5fb87c3fee09c7c50c7dde2 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 11:13:21 +0200 Subject: meta: add index sequence with types as indices --- compat/meta.hpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/compat/meta.hpp b/compat/meta.hpp index b1c1dd1a..900c515f 100644 --- a/compat/meta.hpp +++ b/compat/meta.hpp @@ -1,6 +1,8 @@ #pragma once +#include #include +#include namespace meta { @@ -29,7 +31,20 @@ namespace detail { { using type = inst; }; -} + + template + struct index_sequence_ + { + using part = std::integral_constant; + using type = typename index_sequence_::type; + }; + + template + struct index_sequence_ + { + using type = std::tuple; + }; +} // ns detail template @@ -50,4 +65,7 @@ using butlast = reverse>>; template using last = lift>; -} +template +using index_sequence = typename detail::index_sequence_::type; + +} // ns meta -- cgit v1.2.3 From f8b3c341164fdb336eea43a820af814cff5b6485 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 11:13:47 +0200 Subject: compat/functional: add generic value-constant type --- compat/functional.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/compat/functional.hpp b/compat/functional.hpp index e7229d6e..141bbef7 100644 --- a/compat/functional.hpp +++ b/compat/functional.hpp @@ -38,6 +38,19 @@ inline void maybe_reserve_space(seq_& seq, unsigned sz) } // ns +template +struct constant final +{ + using type = t; + constexpr type operator()() const noexcept + { + return value_; + } + static constexpr type value = value_; + + constant() = delete; +}; + template auto map(F&& fun, const seq_& seq) { -- cgit v1.2.3 From ae2ced1284d3364c3f061044de377cfc624ca02e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 11:14:45 +0200 Subject: cmake: fix var expansion for older cmake versions --- cmake/opentrack-boilerplate.cmake | 2 +- cmake/opentrack-policy.cmake | 32 +++++--------------------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/cmake/opentrack-boilerplate.cmake b/cmake/opentrack-boilerplate.cmake index 7a88e6ef..35ef1d22 100644 --- a/cmake/opentrack-boilerplate.cmake +++ b/cmake/opentrack-boilerplate.cmake @@ -88,7 +88,7 @@ function(otr_compat target) if(CMAKE_COMPILER_IS_GNUCXX) set(c-props "-fvisibility=hidden") - if(NOT linker-lang STREQUAL "C") + if(NOT ".${linker-lang}" STREQUAL ".C") set(c-props "${c-props} -fuse-cxa-atexit") endif() endif() diff --git a/cmake/opentrack-policy.cmake b/cmake/opentrack-policy.cmake index 2d88e218..7ded20f7 100644 --- a/cmake/opentrack-policy.cmake +++ b/cmake/opentrack-policy.cmake @@ -1,27 +1,5 @@ -if(POLICY CMP0020) - cmake_policy(SET CMP0020 NEW) -endif() - -if(POLICY CMP0058) - cmake_policy(SET CMP0058 NEW) -endif() - -if(POLICY CMP0028) - cmake_policy(SET CMP0028 NEW) -endif() - -if(POLICY CMP0042) - cmake_policy(SET CMP0042 NEW) -endif() - -if(POLICY CMP0063) - cmake_policy(SET CMP0063 NEW) -endif() - -if(POLICY CMP0053) - cmake_policy(SET CMP0053 OLD) -endif() - -if(POLICY CMP0011) - cmake_policy(SET CMP0011 NEW) -endif() +foreach(k CMP0020 CMP0058 CMP0028 CMP0042 CMP0063 CMP0053 CMP0011 CMP0054) + if(POLICY ${k}) + cmake_policy(SET ${k} NEW) + endif() +endforeach() -- cgit v1.2.3 From 80deba23647e80895d2942ab2d3b8e247fb68f69 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 11:29:12 +0200 Subject: spline: recompute spline config lazily --- spline/spline.cpp | 16 ++++++++-------- spline/spline.hpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spline/spline.cpp b/spline/spline.cpp index 6167de0d..76a6190f 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -25,7 +25,7 @@ constexpr int spline::value_count; spline::spline(qreal maxx, qreal maxy, const QString& name) : s(nullptr), - data(value_count, -1.f), + data(value_count, -16), _mutex(QMutex::Recursive), max_x(maxx), max_y(maxy), @@ -50,6 +50,7 @@ spline::spline() : spline(0, 0, "") {} void spline::set_tracking_active(bool value) { + QMutexLocker l(&_mutex); activep = value; } @@ -69,14 +70,14 @@ void spline::set_max_input(qreal max_input) { QMutexLocker l(&_mutex); max_x = max_input; - recompute(); + validp = false; } void spline::set_max_output(qreal max_output) { QMutexLocker l(&_mutex); max_y = max_output; - recompute(); + validp = false; } qreal spline::max_input() const @@ -133,6 +134,7 @@ float spline::get_value_internal(int x) { if (!validp) { + recompute(); update_interp_data(); validp = true; } @@ -371,15 +373,14 @@ void spline::set_bundle(bundle b) // spline isn't a QObject and the connection context is incorrect QMutexLocker l(&_mutex); - recompute(); + validp = false; + emit s->recomputed(); }, Qt::QueuedConnection); } - recompute(); - - emit s->recomputed(); + validp = false; } } @@ -423,7 +424,6 @@ void spline::recompute() last_input_value = QPointF(0, 0); activep = false; - validp = false; } // the return value is only safe to use with no spline::set_bundle calls diff --git a/spline/spline.hpp b/spline/spline.hpp index 7098f125..85287e38 100644 --- a/spline/spline.hpp +++ b/spline/spline.hpp @@ -63,7 +63,7 @@ class OTR_SPLINE_EXPORT spline final MyMutex _mutex; QPointF last_input_value; qreal max_x, max_y; - volatile bool activep; + bool activep; bool validp; public: -- cgit v1.2.3 From 3e913cdf543d5d4b2fd297eb27f3536be692100c Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 11:31:12 +0200 Subject: spline: rename, change call site --- spline/spline.cpp | 9 +++++---- spline/spline.hpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/spline/spline.cpp b/spline/spline.cpp index 76a6190f..3c1c3eba 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -134,7 +134,6 @@ float spline::get_value_internal(int x) { if (!validp) { - recompute(); update_interp_data(); validp = true; } @@ -191,6 +190,8 @@ void spline::update_interp_data() { points_t points = s->points; + ensure_valid(points); + int sz = element_count(points, max_x); if (sz == 0) @@ -384,11 +385,11 @@ void spline::set_bundle(bundle b) } } -void spline::recompute() +void spline::ensure_valid(const QList& the_points) { QMutexLocker foo(&_mutex); - QList list = s->points; + QList list = the_points; // storing to s->points fires bundle::changed and that leads to an infinite loop // thus, only store if we can't help it @@ -419,7 +420,7 @@ void spline::recompute() ret_list.push_back(pt); } - if (ret_list != s->points) + if (ret_list != the_points) s->points = ret_list; last_input_value = QPointF(0, 0); diff --git a/spline/spline.hpp b/spline/spline.hpp index 85287e38..328d1ece 100644 --- a/spline/spline.hpp +++ b/spline/spline.hpp @@ -97,7 +97,7 @@ public: void set_tracking_active(bool value); bundle get_bundle(); - void recompute(); + void ensure_valid(const QList& the_points); std::shared_ptr get_settings(); std::shared_ptr get_settings() const; -- cgit v1.2.3 From c114e085b3bb51da51c4a7ecceda146e095c7a2e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 17:25:43 +0200 Subject: compat/util: simplify --- compat/functional.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compat/functional.hpp b/compat/functional.hpp index 141bbef7..893fe1a0 100644 --- a/compat/functional.hpp +++ b/compat/functional.hpp @@ -4,14 +4,12 @@ #include #include -namespace functools -{ - -constexpr void return_void(); - template using remove_qualifiers = std::remove_reference_t>; +namespace functools +{ + template struct reserver_ { @@ -22,7 +20,7 @@ struct reserver_ }; template -struct reserver_().reserve(0u), return_void())> +struct reserver_().reserve(0u), (void)0)> { static inline void maybe_reserve_space(seq_& seq, unsigned sz) { @@ -54,7 +52,7 @@ struct constant final template auto map(F&& fun, const seq_& seq) { - using seq_type = functools::remove_qualifiers; + using seq_type = remove_qualifiers; seq_type ret; std::back_insert_iterator it = std::back_inserter(ret); -- cgit v1.2.3 From 1d3fa41e12c9f17f184084f734fe78a4f1468b60 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 19:21:49 +0200 Subject: pose-widget: add empty space to prevent out-out-bounds writes --- pose-widget/pose-widget.cpp | 33 ++++++++++++++++++--------------- pose-widget/pose-widget.hpp | 2 -- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pose-widget/pose-widget.cpp b/pose-widget/pose-widget.cpp index c3e87dff..54278c34 100644 --- a/pose-widget/pose-widget.cpp +++ b/pose-widget/pose-widget.cpp @@ -18,11 +18,12 @@ using namespace pose_widget_impl; +static constexpr int offset = 2; + pose_transform::pose_transform(QWidget* dst) : dst(dst), - image(w, h, QImage::Format_ARGB32), - image2(w, h, QImage::Format_ARGB32), - width(w), height(h), + image(w+offset*2, h+offset*2, QImage::Format_ARGB32), + image2(w+offset*2, h+offset*2, QImage::Format_ARGB32), fresh(false) { front = QImage(QString(":/images/side1.png")); @@ -43,8 +44,10 @@ pose_transform::~pose_transform() void pose_widget::paintEvent(QPaintEvent* event) { QPainter p(this); - xform.with_image_lock([&](const QImage& image) { - p.drawImage(event->rect(), image); + + xform.with_image_lock([&](const QImage& image) + { + p.drawImage(event->rect(), image, offset, offset); }); } @@ -186,7 +189,7 @@ void pose_transform::project_quad_texture() num dir; vec2 pt[4]; - const int sx = width - 1, sy = height - 1; + const int sx = w - 1, sy = h - 1; vec2 projected[3]; { @@ -252,7 +255,7 @@ void pose_transform::project_quad_texture() const unsigned dest_pitch = image.bytesPerLine(); const unsigned char* orig = tex.bits(); - unsigned char* dest = image.bits(); + unsigned char* dest = image.bits() + offset*dest_pitch; const int orig_depth = tex.depth() / 8; const int dest_depth = image.depth() / 8; @@ -309,7 +312,7 @@ void pose_transform::project_quad_texture() const float ax = 1 - ax_; const float ay = 1 - ay_; - const unsigned pos = y * dest_pitch + x * dest_depth; + const unsigned pos = y * dest_pitch + (x+offset) * dest_depth; for (int k = 0; k < 4; k++) { @@ -336,13 +339,13 @@ vec2 pose_transform::project(const vec3 &point) vec3 ret = rotation * point; num z = std::fmax(num(.5), 1 + translation.z()/-80); - num w = width, h = height; - num x = w * translation.x() / 2 / -80; - if (fabs(x) > w/2) - x = x > 0 ? w/2 : w/-2; - num y = h * translation.y() / 2 / -80; - if (fabs(y) > h/2) - y = y > 0 ? h/2 : h/-2; + num w_ = w, h_ = h; + num x = w_ * translation.x() / 2 / -80; + if (fabs(x) > w_/2) + x = x > 0 ? w_/2 : w_/-2; + num y = h_ * translation.y() / 2 / -80; + if (fabs(y) > h_/2) + y = y > 0 ? h_/2 : h_/-2; return vec2(z * (ret.x() + x), z * (ret.y() + y)); } diff --git a/pose-widget/pose-widget.hpp b/pose-widget/pose-widget.hpp index b528d394..1d34778a 100644 --- a/pose-widget/pose-widget.hpp +++ b/pose-widget/pose-widget.hpp @@ -69,8 +69,6 @@ class pose_transform final : private QThread QImage front, back; QImage image, image2; - int width, height; - std::atomic fresh; static constexpr int w = 320, h = 240; -- cgit v1.2.3 From ad496a028cee3e119177a3a7d9e9f4f0edb3f96c Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 7 May 2017 19:23:32 +0200 Subject: spline: add comment --- spline/spline.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spline/spline.cpp b/spline/spline.cpp index 3c1c3eba..7ca8147c 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -447,6 +447,9 @@ double spline::bucket_size_coefficient(const QList& points) const if (unlikely(max_x < eps)) return 0; + // needed to fill the buckets up to the last control point. + // space between that point and max_x doesn't matter. + const int sz = element_count(points, max_x); const double last_x = sz ? points[sz - 1].x() : max_x; -- cgit v1.2.3 From d160fbec0c70095b725d612458ae9ee3aa8ed526 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:40:49 +0200 Subject: compat/timer: add std::chrono support --- compat/time.hpp | 25 +++++++++++++++++++++++++ compat/timer.cpp | 32 +++++++++++++++++--------------- compat/timer.hpp | 18 +++++++++++++----- 3 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 compat/time.hpp diff --git a/compat/time.hpp b/compat/time.hpp new file mode 100644 index 00000000..fbe7469a --- /dev/null +++ b/compat/time.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace time_units { + +template +using duration = std::chrono::duration; + +template +static inline constexpr auto time_cast(const u& in) +{ + return std::chrono::duration_cast(in); +} + +using secs = duration>; +using secs_ = duration>; +using ms = duration; +using ms_ = duration; +using us = duration; +using us_ = duration; +using ns = duration; + +} // ns time_units diff --git a/compat/timer.cpp b/compat/timer.cpp index d5052ccb..3ecdf528 100644 --- a/compat/timer.cpp +++ b/compat/timer.cpp @@ -7,6 +7,7 @@ */ #include "timer.hpp" +#include Timer::Timer() { @@ -15,17 +16,20 @@ Timer::Timer() void Timer::start() { - wrap_gettime(&state); + gettime(&state); } // common -void Timer::wrap_gettime(timespec* state) +void Timer::gettime(timespec* state) { #if defined(_WIN32) || defined(__MACH__) otr_clock_gettime(state); +#elif defined CLOCK_MONOTONIC + const int res = clock_gettime(CLOCK_MONOTONIC, state); + assert(res == 0 && "must support CLOCK_MONOTONIC"); #else - (void) clock_gettime(CLOCK_MONOTONIC, state); +# error "timer query method not known" #endif } @@ -33,14 +37,13 @@ void Timer::wrap_gettime(timespec* state) long long Timer::elapsed_nsecs() const { - struct timespec cur = {}; - wrap_gettime(&cur); + timespec cur{}; + gettime(&cur); return conv_nsecs(cur); } long long Timer::conv_nsecs(const timespec& cur) const { - // this can and will overflow return (cur.tv_sec - state.tv_sec) * 1000000000LL + (cur.tv_nsec - state.tv_nsec); } @@ -48,8 +51,8 @@ long long Timer::conv_nsecs(const timespec& cur) const double Timer::elapsed_usecs() const { - struct timespec cur = {}; - wrap_gettime(&cur); + timespec cur{}; + gettime(&cur); const long long nsecs = conv_nsecs(cur); return nsecs * 1e-3; } @@ -73,27 +76,26 @@ double Timer::elapsed_seconds() const #if defined _WIN32 LARGE_INTEGER Timer::otr_get_clock_frequency() { - LARGE_INTEGER freq = {}; + LARGE_INTEGER freq{}; (void) QueryPerformanceFrequency(&freq); return freq; } void Timer::otr_clock_gettime(timespec* ts) { - static LARGE_INTEGER freq = otr_get_clock_frequency(); + static const LARGE_INTEGER freq = otr_get_clock_frequency(); LARGE_INTEGER d; (void) QueryPerformanceCounter(&d); using ll = long long; - using ld = long double; - const long long part = ll(d.QuadPart / ld(freq.QuadPart) * 1000000000.L); + const ll part = ll(std::roundl((d.QuadPart * 1000000000.L) / ll(freq.QuadPart))); using t_s = decltype(ts->tv_sec); using t_ns = decltype(ts->tv_nsec); - ts->tv_sec = t_s(part / 1000000000LL); - ts->tv_nsec = t_ns(part % 1000000000LL); + ts->tv_sec = t_s(part / 1000000000); + ts->tv_nsec = t_ns(part % 1000000000); } #elif defined __MACH__ @@ -106,7 +108,7 @@ mach_timebase_info_data_t Timer::otr_get_mach_frequency() double Timer::otr_clock_gettime(timespec* ts) { - static mach_timebase_info_data_t timebase_info = otr_get_mach_frequency(); + static const mach_timebase_info_data_t timebase_info = otr_get_mach_frequency(); uint64_t state, nsec; state = mach_absolute_time(); nsec = state * timebase_info.numer / timebase_info.denom; diff --git a/compat/timer.hpp b/compat/timer.hpp index e9efba79..58e1c7d6 100644 --- a/compat/timer.hpp +++ b/compat/timer.hpp @@ -20,7 +20,9 @@ #include #include -class OTR_COMPAT_EXPORT Timer +#include "time.hpp" + +class OTR_COMPAT_EXPORT Timer final { struct timespec state; long long conv_nsecs(const struct timespec& cur) const; @@ -31,16 +33,22 @@ class OTR_COMPAT_EXPORT Timer static mach_timebase_info_data_t otr_get_mach_frequency(); #endif - static void wrap_gettime(struct timespec* state); + static void gettime(struct timespec* state); + using ns = time_units::ns; public: Timer(); - void start(); + + template + t elapsed() const + { + using namespace time_units; + return static_cast(ns(elapsed_nsecs())); + } + long long elapsed_nsecs() const; double elapsed_usecs() const; double elapsed_ms() const; double elapsed_seconds() const; }; - - -- cgit v1.2.3 From 29ddc08ff2b5e8161f8c342cdb8fdafc9aa4a639 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:41:22 +0200 Subject: cmake: don't relink when no headers change This makes release builds hella fast. --- cmake/opentrack-boilerplate.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/opentrack-boilerplate.cmake b/cmake/opentrack-boilerplate.cmake index 35ef1d22..821de1ba 100644 --- a/cmake/opentrack-boilerplate.cmake +++ b/cmake/opentrack-boilerplate.cmake @@ -128,11 +128,12 @@ endfunction() function(otr_module n_) message(STATUS "module ${n_}") cmake_parse_arguments(arg - "STATIC;NO-COMPAT;BIN;EXECUTABLE;NO-QT;WIN32-CONSOLE;NO-INSTALL" + "STATIC;NO-COMPAT;BIN;EXECUTABLE;NO-QT;WIN32-CONSOLE;NO-INSTALL;RELINK" "LINK;COMPILE" "SOURCES" ${ARGN} ) + if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "") message(FATAL_ERROR "otr_module bad formals: ${arg_UNPARSED_ARGUMENTS}") endif() @@ -166,6 +167,12 @@ function(otr_module n_) add_library(${n} ${link-mode} "${${n}-all}") endif() + if(NOT arg_RELINK) + set_property(TARGET ${n} PROPERTY LINK_DEPENDS_NO_SHARED TRUE) + else() + set_property(TARGET ${n} PROPERTY LINK_DEPENDS_NO_SHARED FALSE) + endif() + if(NOT arg_NO-QT) target_link_libraries(${n} ${MY_QT_LIBS}) endif() -- cgit v1.2.3 From a1f5e2953442655609c6bca03c32a962dd3f1711 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:41:57 +0200 Subject: compat/util: add PROG1, adjust clamp --- compat/util.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compat/util.hpp b/compat/util.hpp index 735fbae6..823b83d1 100644 --- a/compat/util.hpp +++ b/compat/util.hpp @@ -13,10 +13,14 @@ #include #define progn(...) ([&]() { __VA_ARGS__ }()) +#define prog1(x, ...) (([&]() { auto _ret1324 = (x); do { __VA_ARGS__; } while (0); return _ret1324; })()) #define once_only(...) progn(static bool once = false; if (!once) { once = true; __VA_ARGS__; }) - -#define load_time_value(x) progn(static const auto _value132((x)); return _value132;) +#define load_time_value(x) \ + progn( \ + static const auto _value132((x)); \ + return static_cast(value132); \ + ) template using mem = std::shared_ptr; template using ptr = std::unique_ptr; @@ -76,9 +80,9 @@ inline auto clamp_(n val, n min, n max) -> n } template -inline auto clamp(const t& val, const u& min, const w& max) -> decltype(val * min * max) +inline auto clamp(const t& val, const u& min, const w& max) -> decltype(val + min + max) { - return ::util_detail::clamp_(val, min, max); + return ::util_detail::clamp_(val, min, max); } template -- cgit v1.2.3 From f49b67b915dab844239068376478f10bf7ecf71b Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:42:59 +0200 Subject: tracker/realsense: make GNU build less noisy I'm only using it for Coverity builds and it's not expected to work with GNU. --- tracker-rs/rs_impl/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tracker-rs/rs_impl/CMakeLists.txt b/tracker-rs/rs_impl/CMakeLists.txt index 7148cdf1..d4bf0925 100644 --- a/tracker-rs/rs_impl/CMakeLists.txt +++ b/tracker-rs/rs_impl/CMakeLists.txt @@ -3,4 +3,12 @@ if(WIN32) target_compile_definitions(opentrack-tracker-rs-impl PRIVATE -DUNICODE -D_UNICODE) target_include_directories(opentrack-tracker-rs-impl PRIVATE SYSTEM "${SDK_REALSENSE}/include") target_link_libraries(opentrack-tracker-rs-impl advapi32) + + # for SDK headers + if(CMAKE_COMPILER_IS_GNUCC) + add_definitions(-fpermissive -Wno-error -w + #-Wno-missing-field-initializers -Wno-switch -Wno-sign-compare + #-Wno-unknown-pragmas -Wno-attributes + ) + endif() endif() -- cgit v1.2.3 From 8cb6d9d0a5aa617d0d9922ea26f0c98df27b5f1e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:43:09 +0200 Subject: cmake: fix no-op --- csv/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/csv/CMakeLists.txt b/csv/CMakeLists.txt index 82595688..177db52e 100644 --- a/csv/CMakeLists.txt +++ b/csv/CMakeLists.txt @@ -1,2 +1 @@ otr_module(csv) -target_link_libraries(opentrack-csv opentrack-api) -- cgit v1.2.3 From 4c4c783d023cf1bb6a8d7d883bf8d3384f7b7da1 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:43:50 +0200 Subject: minor fixes only --- dinput/keybinding-worker.cpp | 5 +++-- options/connector.cpp | 7 ++++--- options/group.cpp | 4 +++- options/scoped.cpp | 2 +- pose-widget/pose-widget.cpp | 4 ++-- pose-widget/pose-widget.hpp | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/dinput/keybinding-worker.cpp b/dinput/keybinding-worker.cpp index b94b762e..0e16ac71 100644 --- a/dinput/keybinding-worker.cpp +++ b/dinput/keybinding-worker.cpp @@ -9,6 +9,7 @@ #ifdef _WIN32 #include "keybinding-worker.hpp" +#include "compat/util.hpp" #include #include #include @@ -18,8 +19,8 @@ bool Key::should_process() { if (!enabled || (keycode == 0 && guid == "")) return false; - bool ret = !held || timer.elapsed_ms() > 100; - timer.start(); + bool ret = prog1(!held || timer.elapsed_ms() > 100, + timer.start()); return ret; } diff --git a/options/connector.cpp b/options/connector.cpp index 63d70ca7..075a57e1 100644 --- a/options/connector.cpp +++ b/options/connector.cpp @@ -83,11 +83,12 @@ void connector::on_value_created(const QString& name, value_type val) QMutexLocker l(get_mtx()); - if (on_value_destructed_impl(name, val)) + int i = 1; + while (on_value_destructed_impl(name, val)) { qWarning() << "options/connector: value created twice;" - << "bundle" - << val->b->name() + << "cnt" << i++ + << "bundle" << val->b->name() << "value-name" << name << "value-ptr" << quintptr(val); } diff --git a/options/group.cpp b/options/group.cpp index 3f800ff0..60e8a7b4 100644 --- a/options/group.cpp +++ b/options/group.cpp @@ -30,7 +30,9 @@ group::group(const QString& name) : name(name) { auto tmp = k_.toUtf8(); QString k(tmp); - kvs[k] = conf.value(k_); + QVariant val = conf.value(k_); + if (val.type() != QVariant::Invalid) + kvs[k] = std::move(val); } conf.endGroup(); }); diff --git a/options/scoped.cpp b/options/scoped.cpp index 96f4a261..58a4ee02 100644 --- a/options/scoped.cpp +++ b/options/scoped.cpp @@ -2,8 +2,8 @@ #include #include -// for std::abort() #include +#include #include diff --git a/pose-widget/pose-widget.cpp b/pose-widget/pose-widget.cpp index 54278c34..8646df30 100644 --- a/pose-widget/pose-widget.cpp +++ b/pose-widget/pose-widget.cpp @@ -47,7 +47,7 @@ void pose_widget::paintEvent(QPaintEvent* event) xform.with_image_lock([&](const QImage& image) { - p.drawImage(event->rect(), image, offset, offset); + p.drawImage(event->rect(), image, QRect(offset, offset, pose_transform::w, pose_transform::h)); }); } @@ -71,7 +71,7 @@ void pose_transform::run() project_quad_texture(); end: - portable::sleep(9); + portable::sleep(23); } } diff --git a/pose-widget/pose-widget.hpp b/pose-widget/pose-widget.hpp index 1d34778a..a27bf4b9 100644 --- a/pose-widget/pose-widget.hpp +++ b/pose-widget/pose-widget.hpp @@ -37,7 +37,7 @@ using lock_guard = std::unique_lock; class pose_widget; -class pose_transform final : private QThread +struct pose_transform final : private QThread { pose_transform(QWidget* dst); ~pose_transform(); -- cgit v1.2.3 From f7ab2dc5a54c573cd7408a68cb1e93174827719e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:44:05 +0200 Subject: options: split up value.hpp header Also combine the traits classes and make them more useful. --- options/base-value.cpp | 27 ++++++++ options/base-value.hpp | 85 ++++++++++++++++++++++++ options/value-traits.hpp | 50 ++++++++++++++ options/value.cpp | 35 ---------- options/value.hpp | 166 +++++++++-------------------------------------- 5 files changed, 194 insertions(+), 169 deletions(-) create mode 100644 options/base-value.cpp create mode 100644 options/base-value.hpp create mode 100644 options/value-traits.hpp delete mode 100644 options/value.cpp diff --git a/options/base-value.cpp b/options/base-value.cpp new file mode 100644 index 00000000..29f4b496 --- /dev/null +++ b/options/base-value.cpp @@ -0,0 +1,27 @@ +#include "base-value.hpp" + +using namespace options; + +base_value::base_value(bundle b, const QString& name, base_value::comparator cmp, std::type_index type_idx) : + b(b), + self_name(name), + cmp(cmp), + type_index(type_idx) +{ + b->on_value_created(name, this); +} + +base_value::~base_value() +{ + b->on_value_destructed(self_name, this); +} + +void base_value::store(const QVariant& datum) +{ + b->store_kv(self_name, datum); +} + +void ::options::detail::set_base_value_to_default(base_value* val) +{ + val->set_to_default(); +} diff --git a/options/base-value.hpp b/options/base-value.hpp new file mode 100644 index 00000000..4f90e3fc --- /dev/null +++ b/options/base-value.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include "bundle.hpp" +#include "slider.hpp" +#include "connector.hpp" + +#include "export.hpp" + +#include +#include +#include +#include +#include + +#include + +#define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); } +#define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) const + +namespace options { + +class OTR_OPTIONS_EXPORT base_value : public QObject +{ + Q_OBJECT + friend class detail::connector; + + using comparator = bool(*)(const QVariant& val1, const QVariant& val2); +public: + QString name() const { return self_name; } + base_value(bundle b, const QString& name, comparator cmp, std::type_index type_idx); + ~base_value() override; +signals: + OPENTRACK_DEFINE_SIGNAL(double); + OPENTRACK_DEFINE_SIGNAL(float); + OPENTRACK_DEFINE_SIGNAL(int); + OPENTRACK_DEFINE_SIGNAL(bool); + OPENTRACK_DEFINE_SIGNAL(const QString&); + OPENTRACK_DEFINE_SIGNAL(const slider_value&); + OPENTRACK_DEFINE_SIGNAL(const QPointF&); + OPENTRACK_DEFINE_SIGNAL(const QVariant&); + + OPENTRACK_DEFINE_SIGNAL(const QList&); + OPENTRACK_DEFINE_SIGNAL(const QList&); + OPENTRACK_DEFINE_SIGNAL(const QList&); + OPENTRACK_DEFINE_SIGNAL(const QList&); + OPENTRACK_DEFINE_SIGNAL(const QList&); + OPENTRACK_DEFINE_SIGNAL(const QList&); + OPENTRACK_DEFINE_SIGNAL(const QList&); +protected: + bundle b; + QString self_name; + comparator cmp; + std::type_index type_index; + + void store(const QVariant& datum); + + template + void store(const t& datum) + { + b->store_kv(self_name, QVariant::fromValue(datum)); + } + +public slots: + OPENTRACK_DEFINE_SLOT(double) + OPENTRACK_DEFINE_SLOT(int) + OPENTRACK_DEFINE_SLOT(bool) + OPENTRACK_DEFINE_SLOT(const QString&) + OPENTRACK_DEFINE_SLOT(const slider_value&) + OPENTRACK_DEFINE_SLOT(const QPointF&) + OPENTRACK_DEFINE_SLOT(const QVariant&) + + OPENTRACK_DEFINE_SLOT(const QList&) + OPENTRACK_DEFINE_SLOT(const QList&) + OPENTRACK_DEFINE_SLOT(const QList&) + OPENTRACK_DEFINE_SLOT(const QList&) + OPENTRACK_DEFINE_SLOT(const QList&) + OPENTRACK_DEFINE_SLOT(const QList&) + OPENTRACK_DEFINE_SLOT(const QList&) + + virtual void reload() = 0; + virtual void bundle_value_changed() const = 0; + virtual void set_to_default() = 0; +}; + +} //ns options diff --git a/options/value-traits.hpp b/options/value-traits.hpp new file mode 100644 index 00000000..cf12649c --- /dev/null +++ b/options/value-traits.hpp @@ -0,0 +1,50 @@ +#include "export.hpp" + +#include "compat/functional.hpp" +#include "slider.hpp" + +#include + +#include + +namespace options { +namespace detail { + +template +struct default_value_traits +{ + using element_type = remove_qualifiers; + using value_type = u; + + static inline value_type from_value(const value_type& val, const value_type&) { return val; } + static inline value_type from_storage(const element_type& x) { return static_cast(x); } + static inline element_type to_storage(const value_type& val) { return static_cast(val); } +}; + +template +struct value_traits : default_value_traits +{ +}; + +template<> +struct value_traits : default_value_traits +{ + static inline slider_value from_value(const slider_value& val, const slider_value& def) + { + return slider_value(val.cur(), def.min(), def.max()); + } +}; + +// Qt uses int a lot in slots so use it for all enums +template +struct value_traits::value>> : public default_value_traits +{ +}; + +template<> +struct value_traits : public default_value_traits +{ +}; + +} // ns detail +} // ns options diff --git a/options/value.cpp b/options/value.cpp deleted file mode 100644 index d3d24a58..00000000 --- a/options/value.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2015-2016, Stanislaw Halik - - * Permission to use, copy, modify, and/or distribute this - * software for any purpose with or without fee is hereby granted, - * provided that the above copyright notice and this permission - * notice appear in all copies. - */ - -#include "value.hpp" - -namespace options { - -base_value::base_value(bundle b, const QString& name, base_value::comparator cmp, std::type_index type_idx) : - b(b), - self_name(name), - cmp(cmp), - type_index(type_idx) -{ - b->on_value_created(name, this); -} - -base_value::~base_value() -{ - b->on_value_destructed(self_name, this); -} - -namespace detail -{ - void set_base_value_to_default(base_value* val) - { - val->set_to_default(); - } -} - -} // ns options diff --git a/options/value.hpp b/options/value.hpp index 020cbeea..ebb2096c 100644 --- a/options/value.hpp +++ b/options/value.hpp @@ -12,153 +12,59 @@ #include "compat/util.hpp" -#include "connector.hpp" #include "bundle.hpp" #include "slider.hpp" +#include "base-value.hpp" +#include "value-traits.hpp" + +#include #include #include #include +#include + +#include #include #include #include +#include -#define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); } -#define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) const namespace options { namespace detail { -template struct value_type_traits { using type = t;}; -template<> struct value_type_traits { using type = const QString&; }; -template<> struct value_type_traits { using type = const slider_value&; }; -template struct value_type_traits> -{ - using type = const QList&; -}; -template using value_type_t = typename value_type_traits::type; -} - -class OTR_OPTIONS_EXPORT base_value : public QObject -{ - Q_OBJECT - friend class ::options::detail::connector; - using comparator = bool(*)(const QVariant& val1, const QVariant& val2); -public: - QString name() const { return self_name; } - base_value(bundle b, const QString& name, comparator cmp, std::type_index type_idx); - ~base_value() override; -signals: - OPENTRACK_DEFINE_SIGNAL(double); - OPENTRACK_DEFINE_SIGNAL(float); - OPENTRACK_DEFINE_SIGNAL(int); - OPENTRACK_DEFINE_SIGNAL(bool); - OPENTRACK_DEFINE_SIGNAL(const QString&); - OPENTRACK_DEFINE_SIGNAL(const slider_value&); - OPENTRACK_DEFINE_SIGNAL(const QPointF&); - OPENTRACK_DEFINE_SIGNAL(const QVariant&); - - OPENTRACK_DEFINE_SIGNAL(const QList&); - OPENTRACK_DEFINE_SIGNAL(const QList&); - OPENTRACK_DEFINE_SIGNAL(const QList&); - OPENTRACK_DEFINE_SIGNAL(const QList&); - OPENTRACK_DEFINE_SIGNAL(const QList&); - OPENTRACK_DEFINE_SIGNAL(const QList&); - OPENTRACK_DEFINE_SIGNAL(const QList&); -protected: - bundle b; - QString self_name; - comparator cmp; - std::type_index type_index; - - void store(const QVariant& datum) - { - b->store_kv(self_name, datum); - } - - template - void store(const t& datum) - { - b->store_kv(self_name, QVariant::fromValue(datum)); - } +OTR_OPTIONS_EXPORT void acct_lookup(bool is_fresh); -public slots: - OPENTRACK_DEFINE_SLOT(double) - OPENTRACK_DEFINE_SLOT(int) - OPENTRACK_DEFINE_SLOT(bool) - OPENTRACK_DEFINE_SLOT(const QString&) - OPENTRACK_DEFINE_SLOT(const slider_value&) - OPENTRACK_DEFINE_SLOT(const QPointF&) - OPENTRACK_DEFINE_SLOT(const QVariant&) - - OPENTRACK_DEFINE_SLOT(const QList&) - OPENTRACK_DEFINE_SLOT(const QList&) - OPENTRACK_DEFINE_SLOT(const QList&) - OPENTRACK_DEFINE_SLOT(const QList&) - OPENTRACK_DEFINE_SLOT(const QList&) - OPENTRACK_DEFINE_SLOT(const QList&) - OPENTRACK_DEFINE_SLOT(const QList&) - - virtual void reload() = 0; - virtual void bundle_value_changed() const = 0; - virtual void set_to_default() = 0; -}; +} // ns detail -namespace detail { template -struct value_get_traits +class value final : public base_value { - static inline t get(const t& val, const t&) - { - return val; - } -}; + using traits = detail::value_traits; + using element_type = typename traits::element_type; -template<> -struct value_get_traits -{ - using t = slider_value; - static inline t get(const t& val, const t& def) + static bool is_equal(const QVariant& val1, const QVariant& val2) { - return t(val.cur(), def.min(), def.max()); + return val1.value() == val2.value(); } -}; -template -struct value_element_type -{ - using type = typename std::remove_reference::type>::type; -}; - -// Qt uses int a lot in slots so use it for all enums -template -struct value_element_type::value>::type> -{ - using type = int; -}; - -template<> struct value_element_type { using type = double; }; - -template using value_element_type_t = typename value_element_type::type; + OTR_NEVER_INLINE + t get() const + { + if (!b->contains(self_name) || b->get(self_name).type() == QVariant::Invalid) + return def; -} + const element_type x(b->get(self_name)); -template -class value final : public base_value -{ - static bool is_equal(const QVariant& val1, const QVariant& val2) - { - return val1.value() == val2.value(); + return traits::from_value(traits::from_storage(x), def); } public: - using element_type = detail::value_element_type_t; - OTR_NEVER_INLINE t operator=(const t& datum) { - const element_type tmp = static_cast(datum); - if (tmp != get()) - store(tmp); + if (datum != get()) + store(traits::to_storage(datum)); return datum; } @@ -167,13 +73,12 @@ public: OTR_NEVER_INLINE value(bundle b, const QString& name, t def) : - base_value(b, name, &is_equal, std::type_index(typeid(element_type))), def(def) + base_value(b, name, &is_equal, std::type_index(typeid(element_type))), + def(def) { QObject::connect(b.get(), SIGNAL(reloading()), this, SLOT(reload()), DIRECT_CONNTYPE); - if (!b->contains(name) || b->get(name).type() == QVariant::Invalid) - *this = def; } OTR_NEVER_INLINE @@ -181,6 +86,7 @@ public: { } + OTR_NEVER_INLINE t default_value() const { return def; @@ -193,7 +99,7 @@ public: } OTR_NEVER_INLINE - operator t() const { return get(); } + operator t() const { return std::forward(get()); } OTR_NEVER_INLINE void reload() override @@ -201,34 +107,26 @@ public: *this = static_cast(*this); } + OTR_NEVER_INLINE void bundle_value_changed() const override { - emit valueChanged(static_cast>(get())); + emit valueChanged(traits::to_storage(get())); } OTR_NEVER_INLINE t operator()() const { - return static_cast(get()); + return get(); } template OTR_NEVER_INLINE u to() const { - return static_cast(get()); + return static_cast(std::forward(get())); } private: - OTR_NEVER_INLINE - t get() const - { - t val = b->contains(self_name) - ? static_cast(b->get(self_name)) - : def; - return detail::value_get_traits::get(val, def); - } - const t def; }; -- cgit v1.2.3 From eebafd92fc40f303cef38746a4007b0554a49299 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:45:18 +0200 Subject: logic/tracker: use std::chrono --- logic/tracker.cpp | 22 ++++++++++++---------- logic/tracker.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/logic/tracker.cpp b/logic/tracker.cpp index 7411d3b4..8367ee2f 100644 --- a/logic/tracker.cpp +++ b/logic/tracker.cpp @@ -24,6 +24,7 @@ using namespace euler; using namespace gui_tracker_impl; +using namespace time_units; constexpr double Tracker::r2d; constexpr double Tracker::d2r; @@ -32,7 +33,7 @@ Tracker::Tracker(Mappings& m, SelectedLibraries& libs, TrackLogger& logger) : m(m), libs(libs), logger(logger), - backlog_time(0), + backlog_time(ns(0)), tracking_started(false) { } @@ -403,21 +404,22 @@ void Tracker::run() { logic(); - static constexpr long const_sleep_us = 4000; - const long elapsed_usecs = t.elapsed_usecs(); - t.start(); + static constexpr ns const_sleep_ms(time_cast(ms(4))); + const ns elapsed_nsecs = prog1(t.elapsed(), t.start()); - backlog_time += elapsed_usecs - const_sleep_us; + backlog_time += ns(elapsed_nsecs - const_sleep_ms); - if (std::fabs(backlog_time) > 3000 * 1000) + if (backlog_time > secs_(3) || backlog_time < secs_(-3)) { - qDebug() << "tracker: backlog interval overflow" << backlog_time; - backlog_time = 0; + qDebug() << "tracker: backlog interval overflow" + << time_cast(backlog_time).count() << "ms"; + backlog_time = backlog_time.zero(); } - const unsigned sleep_time = unsigned(std::round(clamp((const_sleep_us - backlog_time)/1000., 0, const_sleep_us*2.5/1000))); + const int sleep_time_ms = iround(clamp(const_sleep_ms - backlog_time, + ns(0), ms(50)).count()); - portable::sleep(sleep_time); + portable::sleep(sleep_time_ms); } { diff --git a/logic/tracker.h b/logic/tracker.h index 85bd1ed8..2f29aca7 100644 --- a/logic/tracker.h +++ b/logic/tracker.h @@ -85,7 +85,7 @@ private: state real_rotation, scaled_rotation; euler_t t_center; - long backlog_time; + time_units::ns backlog_time; bool tracking_started; -- cgit v1.2.3 From 5e5dc9ec086eb277828abd6bade93dd0faabb9de Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:46:22 +0200 Subject: tracker/hatire: try to fix busy-looping harder Need discussion in: #139 --- tracker-hatire/thread.cpp | 60 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/tracker-hatire/thread.cpp b/tracker-hatire/thread.cpp index fa09e5da..9dd22c9d 100644 --- a/tracker-hatire/thread.cpp +++ b/tracker-hatire/thread.cpp @@ -89,6 +89,7 @@ hatire_thread::~hatire_thread() hatire_thread::hatire_thread() { data_read.reserve(65536); + com_port.setReadBufferSize(2048); connect(this, &QThread::finished, this, &hatire_thread::teardown_serial, Qt::DirectConnection); connect(this, &hatire_thread::init_serial_port, this, &hatire_thread::init_serial_port_impl, Qt::QueuedConnection); @@ -303,34 +304,71 @@ void hatire_thread::serial_info_impl() void hatire_thread::on_serial_read() { + static char buf[256]; + int sz; + +#if !defined HATIRE_DEBUG_LOGFILE + bool error = false, empty = false; +#endif + { QMutexLocker lck(&data_mtx); + #ifndef HATIRE_DEBUG_LOGFILE - data_read += com_port.readAll(); + sz = com_port.read(buf, sizeof(buf)); + error |= sz < 0; + empty |= sz == 0; #else - QByteArray tmp = com_port.read(30); - data_read += tmp; - if (tmp.length() == 0 && read_timer.isActive()) + const int sz = com_port.read(buf, sizeof(buf)); + + if (sz <= 0 && read_timer.isActive()) { + if (sz < 0) + qDebug() << "hatire: debug file read error" << com_port.errorString(); qDebug() << "eof"; read_timer.stop(); + return; } #endif } - stat.input(timer.elapsed_ms()); - timer.start(); +#if !defined HATIRE_DEBUG_LOGFILE + if (error || com_port.error() != QSerialPort::NoError) + { + once_only(qDebug() << "hatire serial: error num" << com_port.error() << "num2" << error); + com_port.clearError(); // XXX must test it + } + else if (empty) + once_only(qDebug() << "hatire serial: empty"); + else + goto ok; +#endif + + goto fail; + +ok: + data_read.append(buf, sz); + + using namespace time_units; - if (throttle_timer.elapsed_ms() >= 3000) + stat.input(prog1(timer.elapsed().count(), timer.start())); + + if (throttle_timer.elapsed_seconds() >= 1) { throttle_timer.start(); - qDebug() << "stat:" << "avg" << stat.avg() << "stddev" << stat.stddev(); + qDebug() << "hatire stat:" << "avg" << stat.avg() << "stddev" << stat.stddev(); } - if (s.serial_bug_workaround) + if (!s.serial_bug_workaround) + return; + +fail: + // qt can fire QSerialPort::readyRead() needlessly, causing a busy loop. + // see https://github.com/opentrack/opentrack/issues/327#issuecomment-207941003 + + once_only(qDebug() << "hatire: sleeping due to error, pinout:" << int(com_port.pinoutSignals())); + { - // qt can fire QSerialPort::readyRead() needlessly, causing a busy loop. - // see https://github.com/opentrack/opentrack/issues/327#issuecomment-207941003 constexpr int hz = 90; constexpr int ms = 1000/hz; portable::sleep(ms); -- cgit v1.2.3 From c392181211b245e74292424500265323c960c1aa Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 12 May 2017 15:46:50 +0200 Subject: bin: add drmemory suppressions --- bin/drmemory-suppressions.txt | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 bin/drmemory-suppressions.txt diff --git a/bin/drmemory-suppressions.txt b/bin/drmemory-suppressions.txt new file mode 100644 index 00000000..1f94c108 --- /dev/null +++ b/bin/drmemory-suppressions.txt @@ -0,0 +1,43 @@ +UNADDRESSABLE ACCESS +name=false positive 1 +Qt5Gui.dll!qt_blend_argb32_on_argb32_ssse3 + +INVALID HEAP ARGUMENT +name=stfu qtcore +Qt5Core.dll!* + +INVALID HEAP ARGUMENT +name=stfu qwindows 1 +qwindows.dll!* + +LEAK +name=stfu qwindows 2 +qwindows.dll!* + +INVALID HEAP ARGUMENT +name=stfu qtgui +Qt5Gui.dll!* + +INVALID HEAP ARGUMENT +name=stfu sixense 1 +sixense.dll!* + +UNADDRESSABLE ACCESS +name=stfu sixense 2 +sixense.dll!* + +UNINITIALIZED READ +name=dinput +system call NtUserGetRawInputDeviceInfo parameter value #2 + +LEAK +name=stfu leak qtcore 1 +Qt5Core.dll!* + +LEAK +name=cv 1 +opentrack-tracker-pt.dll!cv::`dynamic initializer for '__initialization_mutex_initializer'' + +LEAK +name=cv 2 +opentrack-tracker-aruco.dll!cv::`dynamic initializer for '__initialization_mutex_initializer'' \ No newline at end of file -- cgit v1.2.3