From 5ed05b699e5367bae21828f533e3d169b9bab348 Mon Sep 17 00:00:00 2001 From: Soeren Apel Date: Fri, 26 May 2017 16:19:56 +0200 Subject: [PATCH] Rework signaling mechanism for trace repainting Before, analog traces would request a repaint of the entire view when they receive data. To understand how bad this was, consider 4 enabled analog channels during capture. Every time one channel would receive a bunch of sample data, it would force a repaint of the view, resulting in 4 unnecessary repaints. To fix this, the analog traces no longer request a repaint on incoming sample data. Instead, the mechanism now is such that the view "collates" repaint requests from all used signalbases by means of a one-shot timer, i.e. any repaint request is ignored if the timer is already running. With the timer, we can also establish an upper bound on how often the trace should update at most, currently 25Hz. Since this functionality is very useful for any kind of view, the existing one-shot timer was moved to the ViewBase and then extended as explained. --- pv/view/analogsignal.cpp | 3 --- pv/view/trace.cpp | 5 +++++ pv/view/trace.hpp | 9 ++++++++ pv/view/view.cpp | 22 +++---------------- pv/view/view.hpp | 12 +++++------ pv/views/viewbase.cpp | 46 +++++++++++++++++++++++++++++++++++----- pv/views/viewbase.hpp | 25 ++++++++++++++++++++-- 7 files changed, 87 insertions(+), 35 deletions(-) diff --git a/pv/view/analogsignal.cpp b/pv/view/analogsignal.cpp index 10673556..31c482d6 100644 --- a/pv/view/analogsignal.cpp +++ b/pv/view/analogsignal.cpp @@ -726,9 +726,6 @@ void AnalogSignal::populate_popup_form(QWidget *parent, QFormLayout *form) void AnalogSignal::on_samples_added() { perform_autoranging(false, false); - - if (owner_) - owner_->row_item_appearance_changed(false, true); } void AnalogSignal::on_pos_vdivs_changed(int vdivs) diff --git a/pv/view/trace.cpp b/pv/view/trace.cpp index e1b51373..2154f8a7 100644 --- a/pv/view/trace.cpp +++ b/pv/view/trace.cpp @@ -59,6 +59,11 @@ Trace::Trace(shared_ptr channel) : this, SLOT(on_colour_changed(const QColor&))); } +shared_ptr Trace::base() const +{ + return base_; +} + void Trace::paint_label(QPainter &p, const QRect &rect, bool hover) { const int y = get_visual_y(); diff --git a/pv/view/trace.hpp b/pv/view/trace.hpp index 731ed5db..b6b15198 100644 --- a/pv/view/trace.hpp +++ b/pv/view/trace.hpp @@ -38,6 +38,10 @@ class QFormLayout; namespace pv { +namespace data { +class SignalBase; +} + namespace widgets { class Popup; } @@ -60,6 +64,11 @@ protected: Trace(shared_ptr channel); public: + /** + * Returns the underlying SignalBase instance. + */ + shared_ptr base() const; + /** * Sets the name of the signal. */ diff --git a/pv/view/view.cpp b/pv/view/view.cpp index 97a6bcf7..772a95e0 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -96,7 +96,6 @@ const Timestamp View::MaxScale("1e9"); const Timestamp View::MinScale("1e-12"); const int View::MaxScrollValue = INT_MAX / 2; -const int View::MaxViewAutoUpdateRate = 25; // No more than 25 Hz with sticky scrolling const int View::ScaleUnits[3] = {1, 2, 5}; @@ -178,11 +177,6 @@ View::View(Session &session, bool is_main_view, QWidget *parent) : this, SLOT(process_sticky_events())); lazy_event_handler_.setSingleShot(true); - connect(&delayed_view_updater_, SIGNAL(timeout()), - this, SLOT(perform_delayed_view_update())); - delayed_view_updater_.setSingleShot(true); - delayed_view_updater_.setInterval(1000 / MaxViewAutoUpdateRate); - /* To let the scroll area fill up the parent QWidget (this), we need a layout */ QHBoxLayout *layout = new QHBoxLayout(this); setLayout(layout); @@ -224,11 +218,13 @@ unordered_set< shared_ptr > View::signals() const void View::clear_signals() { + ViewBase::clear_signalbases(); signals_.clear(); } void View::add_signal(const shared_ptr signal) { + ViewBase::add_signalbase(signal->base()); signals_.insert(signal); } @@ -992,6 +988,7 @@ void View::extents_changed(bool horz, bool vert) sticky_events_ |= (horz ? TraceTreeItemHExtentsChanged : 0) | (vert ? TraceTreeItemVExtentsChanged : 0); + lazy_event_handler_.start(); } @@ -1235,19 +1232,6 @@ void View::capture_state_updated(int state) } } -void View::data_updated() -{ - if (always_zoom_to_fit_ || sticky_scrolling_) { - if (!delayed_view_updater_.isActive()) - delayed_view_updater_.start(); - } else { - determine_time_unit(); - update_scroll(); - ruler_->update(); - viewport_->update(); - } -} - void View::perform_delayed_view_update() { if (always_zoom_to_fit_) { diff --git a/pv/view/view.hpp b/pv/view/view.hpp index 9fac1a67..ce89a6bc 100644 --- a/pv/view/view.hpp +++ b/pv/view/view.hpp @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -54,6 +53,10 @@ namespace pv { class Session; +namespace data { +class Logic; +} + namespace views { namespace TraceView { @@ -92,7 +95,6 @@ private: static const pv::util::Timestamp MinScale; static const int MaxScrollValue; - static const int MaxViewAutoUpdateRate; static const int ScaleUnits[3]; @@ -109,7 +111,7 @@ public: virtual void clear_signals(); - virtual void add_signal(const shared_ptr signal); + void add_signal(const shared_ptr signal); #ifdef ENABLE_DECODE virtual void clear_decode_signals(); @@ -352,9 +354,8 @@ private Q_SLOTS: void signals_changed(); void capture_state_updated(int state); - void data_updated(); - void perform_delayed_view_update(); + virtual void perform_delayed_view_update(); void process_sticky_events(); @@ -419,7 +420,6 @@ private: bool sticky_scrolling_; bool coloured_bg_; bool always_zoom_to_fit_; - QTimer delayed_view_updater_; pv::util::Timestamp tick_period_; pv::util::SIPrefix tick_prefix_; diff --git a/pv/views/viewbase.cpp b/pv/views/viewbase.cpp index 03e135c3..e86a543e 100644 --- a/pv/views/viewbase.cpp +++ b/pv/views/viewbase.cpp @@ -32,6 +32,8 @@ using std::shared_ptr; namespace pv { namespace views { +const int ViewBase::MaxViewAutoUpdateRate = 25; // No more than 25 Hz + ViewBase::ViewBase(Session &session, bool is_main_view, QWidget *parent) : session_(session), is_main_view_(is_main_view) @@ -42,10 +44,11 @@ ViewBase::ViewBase(Session &session, bool is_main_view, QWidget *parent) : this, SLOT(signals_changed())); connect(&session_, SIGNAL(capture_state_changed(int)), this, SLOT(capture_state_updated(int))); - connect(&session_, SIGNAL(data_received()), - this, SLOT(data_updated())); - connect(&session_, SIGNAL(frame_ended()), - this, SLOT(data_updated())); + + connect(&delayed_view_updater_, SIGNAL(timeout()), + this, SLOT(perform_delayed_view_update())); + delayed_view_updater_.setSingleShot(true); + delayed_view_updater_.setInterval(1000 / MaxViewAutoUpdateRate); } Session& ViewBase::session() @@ -62,6 +65,33 @@ void ViewBase::clear_signals() { } +unordered_set< shared_ptr > ViewBase::signalbases() const +{ + return signalbases_; +} + +void ViewBase::clear_signalbases() +{ + for (shared_ptr signalbase : signalbases_) { + disconnect(signalbase.get(), SIGNAL(samples_cleared()), + this, SLOT(on_data_updated())); + disconnect(signalbase.get(), SIGNAL(samples_added(QObject*, uint64_t, uint64_t)), + this, SLOT(on_data_updated())); + } + + signalbases_.clear(); +} + +void ViewBase::add_signalbase(const shared_ptr signalbase) +{ + signalbases_.insert(signalbase); + + connect(signalbase.get(), SIGNAL(samples_cleared()), + this, SLOT(on_data_updated())); + connect(signalbase.get(), SIGNAL(samples_added(QObject*, uint64_t, uint64_t)), + this, SLOT(on_data_updated())); +} + #ifdef ENABLE_DECODE void ViewBase::clear_decode_signals() { @@ -102,8 +132,14 @@ void ViewBase::capture_state_updated(int state) (void)state; } -void ViewBase::data_updated() +void ViewBase::perform_delayed_view_update() +{ +} + +void ViewBase::on_data_updated() { + if (!delayed_view_updater_.isActive()) + delayed_view_updater_.start(); } } // namespace views diff --git a/pv/views/viewbase.hpp b/pv/views/viewbase.hpp index 45aae7f1..61430136 100644 --- a/pv/views/viewbase.hpp +++ b/pv/views/viewbase.hpp @@ -23,15 +23,17 @@ #include #include -#include +#include #include +#include #include #include #include using std::shared_ptr; +using std::unordered_set; namespace pv { @@ -53,6 +55,9 @@ class ViewBase : public QWidget { Q_OBJECT +private: + static const int MaxViewAutoUpdateRate; + public: explicit ViewBase(Session &session, bool is_main_view = false, QWidget *parent = nullptr); @@ -61,6 +66,15 @@ public: virtual void clear_signals(); + /** + * Returns the signal bases contained in this view. + */ + unordered_set< shared_ptr > signalbases() const; + + virtual void clear_signalbases(); + + virtual void add_signalbase(const shared_ptr signalbase); + #ifdef ENABLE_DECODE virtual void clear_decode_signals(); @@ -77,7 +91,10 @@ public Q_SLOTS: virtual void trigger_event(util::Timestamp location); virtual void signals_changed(); virtual void capture_state_updated(int state); - virtual void data_updated(); + virtual void perform_delayed_view_update(); + +private Q_SLOTS: + void on_data_updated(); protected: Session &session_; @@ -85,6 +102,10 @@ protected: const bool is_main_view_; util::TimeUnit time_unit_; + + unordered_set< shared_ptr > signalbases_; + + QTimer delayed_view_updater_; }; } // namespace views -- 2.30.2