]> git.sesse.net Git - nageru/commitdiff
Filter Qt signals about updated names and colors.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 2 May 2016 19:44:02 +0000 (21:44 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 2 May 2016 20:05:21 +0000 (22:05 +0200)
This is rather painful and should not be needed, but evidently Qt
can build up unbounded signals/slots queues if we send too often
(and “too often” is seemingly mere hundreds of messages per second).

glwidget.cpp
glwidget.h
mainwindow.cpp
mainwindow.h
mixer.cpp
mixer.h

index f8e76c771402e6688e9be75e601a3f08c8230894..82d702fa1947c85f2ff9f742dbfa50216dc624a4 100644 (file)
@@ -58,12 +58,20 @@ void GLWidget::initializeGL()
        });
        global_mixer->set_frame_ready_callback(output, [this]{
                QMetaObject::invokeMethod(this, "update", Qt::AutoConnection);
-               emit transition_names_updated(global_mixer->get_transition_names());
-               emit resolution_updated(output);
-               emit color_updated(output);
        });
-
+       if (output == Mixer::OUTPUT_LIVE) {
+               global_mixer->set_transition_names_updated_callback(output, [this](const vector<string> &names){
+                       emit transition_names_updated(names);
+               });
+       }
        if (output >= Mixer::OUTPUT_INPUT0) {
+               global_mixer->set_name_updated_callback(output, [this](const string &name){
+                       emit name_updated(output, name);
+               });
+               global_mixer->set_color_updated_callback(output, [this](const string &color){
+                       emit color_updated(output, color);
+               });
+
                int signal_num = global_mixer->get_channel_signal(output);
                if (signal_num != -1) {
                        setContextMenuPolicy(Qt::CustomContextMenu);
index a4b54adffecb7374c7b7a36d12a0e63f100102f8..3eb55dad47550562307546c3c74a7bce2d577c91 100644 (file)
@@ -46,8 +46,8 @@ protected:
 signals:
        void clicked();
        void transition_names_updated(std::vector<std::string> transition_names);
-       void resolution_updated(Mixer::Output output);
-       void color_updated(Mixer::Output output);
+       void name_updated(Mixer::Output output, const std::string &name);
+       void color_updated(Mixer::Output output, const std::string &color);
 
 private slots:
        void show_context_menu(unsigned signal_num, const QPoint &pos);
index 2d2f52e20d3639b75127dd3291807e959d15c5e8..9bac15a822c46d46d830a9047221144b0b8dbe69 100644 (file)
@@ -30,6 +30,7 @@ class QResizeEvent;
 using namespace std;
 using namespace std::placeholders;
 
+Q_DECLARE_METATYPE(std::string);
 Q_DECLARE_METATYPE(std::vector<std::string>);
 
 MainWindow *global_mainwindow = nullptr;
@@ -72,6 +73,7 @@ MainWindow::MainWindow()
        transition_btn1 = ui->transition_btn1;
        transition_btn2 = ui->transition_btn2;
        transition_btn3 = ui->transition_btn3;
+       qRegisterMetaType<string>("std::string");
        qRegisterMetaType<vector<string>>("std::vector<std::string>");
        connect(ui->me_preview, &GLWidget::transition_names_updated, this, &MainWindow::set_transition_names);
        qRegisterMetaType<Mixer::Output>("Mixer::Output");
@@ -106,7 +108,7 @@ void MainWindow::mixer_created(Mixer *mixer)
                connect(ui_display->display, &GLWidget::clicked, bind(&MainWindow::channel_clicked, this, i));
 
                // Let the theme update the text whenever the resolution or color changed.
-               connect(ui_display->display, &GLWidget::resolution_updated, this, &MainWindow::update_channel_name);
+               connect(ui_display->display, &GLWidget::name_updated, this, &MainWindow::update_channel_name);
                connect(ui_display->display, &GLWidget::color_updated, this, &MainWindow::update_channel_color);
 
                // Hook up the keyboard key.
@@ -351,19 +353,18 @@ void MainWindow::set_transition_names(vector<string> transition_names)
        }
 }
 
-void MainWindow::update_channel_name(Mixer::Output output)
+void MainWindow::update_channel_name(Mixer::Output output, const string &name)
 {
        if (output >= Mixer::OUTPUT_INPUT0) {
                unsigned channel = output - Mixer::OUTPUT_INPUT0;
-               previews[channel]->label->setText(global_mixer->get_channel_name(output).c_str());
+               previews[channel]->label->setText(name.c_str());
        }
 }
 
-void MainWindow::update_channel_color(Mixer::Output output)
+void MainWindow::update_channel_color(Mixer::Output output, const string &color)
 {
        if (output >= Mixer::OUTPUT_INPUT0) {
                unsigned channel = output - Mixer::OUTPUT_INPUT0;
-               string color = global_mixer->get_channel_color(output);
                previews[channel]->frame->setStyleSheet(QString::fromStdString("background-color:" + color));
        }
 }
index be80bc8a991abfa29161c1636a929a098aa0ab56..e6d0880cc20f85017ea2d09cb611c35eb544c88f 100644 (file)
@@ -39,8 +39,8 @@ public slots:
        void channel_clicked(int channel_number);
        void wb_button_clicked(int channel_number);
        void set_transition_names(std::vector<std::string> transition_names);
-       void update_channel_name(Mixer::Output output);
-       void update_channel_color(Mixer::Output output);
+       void update_channel_name(Mixer::Output output, const std::string &name);
+       void update_channel_color(Mixer::Output output, const std::string &color);
        void gain_staging_knob_changed(int value);
        void final_makeup_gain_knob_changed(int value);
        void cutoff_knob_changed(int value);
index 597585c1c5ec0c7c7231c6f95695565342491160..fd982a5708d61d59f4dfca1204cd7dc6dda2e5d5 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -142,6 +142,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards)
        theme.reset(new Theme(global_flags.theme_filename.c_str(), resource_pool.get(), num_cards));
        for (unsigned i = 0; i < NUM_OUTPUTS; ++i) {
                output_channel[i].parent = this;
+               output_channel[i].channel = i;
        }
 
        ImageFormat inout_format;
@@ -1140,9 +1141,47 @@ void Mixer::OutputChannel::output_frame(DisplayFrame frame)
                has_ready_frame = true;
        }
 
-       if (has_new_frame_ready_callback) {
+       if (new_frame_ready_callback) {
                new_frame_ready_callback();
        }
+
+       // Reduce the number of callbacks by filtering duplicates. The reason
+       // why we bother doing this is that Qt seemingly can get into a state
+       // where its builds up an essentially unbounded queue of signals,
+       // consuming more and more memory, and there's no good way of collapsing
+       // user-defined signals or limiting the length of the queue.
+       if (transition_names_updated_callback) {
+               vector<string> transition_names = global_mixer->get_transition_names();
+               bool changed = false;
+               if (transition_names.size() != last_transition_names.size()) {
+                       changed = true;
+               } else {
+                       for (unsigned i = 0; i < transition_names.size(); ++i) {
+                               if (transition_names[i] != last_transition_names[i]) {
+                                       changed = true;
+                                       break;
+                               }
+                       }
+               }
+               if (changed) {
+                       transition_names_updated_callback(transition_names);
+                       last_transition_names = transition_names;
+               }
+       }
+       if (name_updated_callback) {
+               string name = global_mixer->get_channel_name(channel);
+               if (name != last_name) {
+                       name_updated_callback(name);
+                       last_name = name;
+               }
+       }
+       if (color_updated_callback) {
+               string color = global_mixer->get_channel_color(channel);
+               if (color != last_color) {
+                       color_updated_callback(color);
+                       last_color = color;
+               }
+       }
 }
 
 bool Mixer::OutputChannel::get_display_frame(DisplayFrame *frame)
@@ -1173,7 +1212,21 @@ bool Mixer::OutputChannel::get_display_frame(DisplayFrame *frame)
 void Mixer::OutputChannel::set_frame_ready_callback(Mixer::new_frame_ready_callback_t callback)
 {
        new_frame_ready_callback = callback;
-       has_new_frame_ready_callback = true;
+}
+
+void Mixer::OutputChannel::set_transition_names_updated_callback(Mixer::transition_names_updated_callback_t callback)
+{
+       transition_names_updated_callback = callback;
+}
+
+void Mixer::OutputChannel::set_name_updated_callback(Mixer::name_updated_callback_t callback)
+{
+       name_updated_callback = callback;
+}
+
+void Mixer::OutputChannel::set_color_updated_callback(Mixer::color_updated_callback_t callback)
+{
+       color_updated_callback = callback;
 }
 
 mutex RefCountedGLsync::fence_lock;
diff --git a/mixer.h b/mixer.h
index dab567f1e80728f668eeb5a26fc8467edcff9ed1..6a58575febd61d230b5e0cb7c65a6771a66248e5 100644 (file)
--- a/mixer.h
+++ b/mixer.h
@@ -147,6 +147,25 @@ public:
                output_channel[output].set_frame_ready_callback(callback);
        }
 
+       // TODO: Should this really be per-channel? Shouldn't it just be called for e.g. the live output?
+       typedef std::function<void(const std::vector<std::string> &)> transition_names_updated_callback_t;
+       void set_transition_names_updated_callback(Output output, transition_names_updated_callback_t callback)
+       {
+               output_channel[output].set_transition_names_updated_callback(callback);
+       }
+
+       typedef std::function<void(const std::string &)> name_updated_callback_t;
+       void set_name_updated_callback(Output output, name_updated_callback_t callback)
+       {
+               output_channel[output].set_name_updated_callback(callback);
+       }
+
+       typedef std::function<void(const std::string &)> color_updated_callback_t;
+       void set_color_updated_callback(Output output, color_updated_callback_t callback)
+       {
+               output_channel[output].set_color_updated_callback(callback);
+       }
+
        typedef std::function<void(float level_lufs, float peak_db,
                                   float global_level_lufs, float range_low_lufs, float range_high_lufs,
                                   float gain_staging_db, float final_makeup_gain_db,
@@ -426,16 +445,25 @@ private:
                void output_frame(DisplayFrame frame);
                bool get_display_frame(DisplayFrame *frame);
                void set_frame_ready_callback(new_frame_ready_callback_t callback);
+               void set_transition_names_updated_callback(transition_names_updated_callback_t callback);
+               void set_name_updated_callback(name_updated_callback_t callback);
+               void set_color_updated_callback(color_updated_callback_t callback);
 
        private:
                friend class Mixer;
 
+               unsigned channel;
                Mixer *parent = nullptr;  // Not owned.
                std::mutex frame_mutex;
                DisplayFrame current_frame, ready_frame;  // protected by <frame_mutex>
                bool has_current_frame = false, has_ready_frame = false;  // protected by <frame_mutex>
                new_frame_ready_callback_t new_frame_ready_callback;
-               bool has_new_frame_ready_callback = false;
+               transition_names_updated_callback_t transition_names_updated_callback;
+               name_updated_callback_t name_updated_callback;
+               color_updated_callback_t color_updated_callback;
+
+               std::vector<std::string> last_transition_names;
+               std::string last_name, last_color;
        };
        OutputChannel output_channel[NUM_OUTPUTS];