From 7dec19543c858de7247f64f6c82f613f9fe05825 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 2 May 2016 21:44:02 +0200 Subject: [PATCH] Filter Qt signals about updated names and colors. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 | 16 ++++++++++---- glwidget.h | 4 ++-- mainwindow.cpp | 11 +++++----- mainwindow.h | 4 ++-- mixer.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-- mixer.h | 30 +++++++++++++++++++++++++- 6 files changed, 106 insertions(+), 16 deletions(-) diff --git a/glwidget.cpp b/glwidget.cpp index f8e76c7..82d702f 100644 --- a/glwidget.cpp +++ b/glwidget.cpp @@ -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 &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); diff --git a/glwidget.h b/glwidget.h index a4b54ad..3eb55da 100644 --- a/glwidget.h +++ b/glwidget.h @@ -46,8 +46,8 @@ protected: signals: void clicked(); void transition_names_updated(std::vector 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); diff --git a/mainwindow.cpp b/mainwindow.cpp index 2d2f52e..9bac15a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -30,6 +30,7 @@ class QResizeEvent; using namespace std; using namespace std::placeholders; +Q_DECLARE_METATYPE(std::string); Q_DECLARE_METATYPE(std::vector); 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("std::string"); qRegisterMetaType>("std::vector"); connect(ui->me_preview, &GLWidget::transition_names_updated, this, &MainWindow::set_transition_names); qRegisterMetaType("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 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)); } } diff --git a/mainwindow.h b/mainwindow.h index be80bc8..e6d0880 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -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 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); diff --git a/mixer.cpp b/mixer.cpp index 597585c..fd982a5 100644 --- 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 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 dab567f..6a58575 100644 --- 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 &)> 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 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 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 bool has_current_frame = false, has_ready_frame = false; // protected by 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 last_transition_names; + std::string last_name, last_color; }; OutputChannel output_channel[NUM_OUTPUTS]; -- 2.39.2