From c842148b9a0b4fb62e288af2eb0f4f4ab99202ff Mon Sep 17 00:00:00 2001 From: Simran Brucherseifer Date: Wed, 29 Apr 2020 11:15:09 +0200 Subject: [PATCH 1/8] MSVC: Build with Multiple Processes (CMAKE_CXX_FLAGS /MP) --- app/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 0c9c4661f..7ca786649 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -92,6 +92,7 @@ if(MSVC) /external:anglebrackets /external:W0 "$<$:/O2>" + "$<$:/MP>" ) else() target_compile_options( From df97a86dbcf5a1f2a860ed485606bcee98aeda99 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 5 May 2020 22:32:11 +0100 Subject: [PATCH 2/8] Fix first usable stream being selected Footage Properties should always select the first usable stream. Commit 1fa3f4e didn't quite fix this with all footage. This should. --- app/dialog/footageproperties/footageproperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/dialog/footageproperties/footageproperties.cpp b/app/dialog/footageproperties/footageproperties.cpp index 3fe507906..484127021 100644 --- a/app/dialog/footageproperties/footageproperties.cpp +++ b/app/dialog/footageproperties/footageproperties.cpp @@ -109,7 +109,7 @@ FootagePropertiesDialog::FootagePropertiesDialog(QWidget *parent, Footage *foota // Auto-select first item that actually has properties if (first_usable_stream >= 0) { - track_list->item(first_usable_stream)->setSelected(true); + track_list->setCurrentRow(first_usable_stream); } track_list->setFocus(); } From c61adbf2a2cefe8ee44be1b4fc0f9772bb564632 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 00:56:16 +1000 Subject: [PATCH 3/8] videorenderer: if an InvalidateVisible() signal comes through, cancel the queue Optimization that frees up the GPU as quickly as possible when the user starts making changes that may require quick feedback. --- app/render/backend/audiorenderbackend.cpp | 4 +- app/render/backend/audiorenderbackend.h | 2 +- app/render/backend/renderbackend.cpp | 46 ++++++++++++++--------- app/render/backend/renderbackend.h | 6 ++- app/render/backend/videorenderbackend.cpp | 24 ++++++++++-- app/render/backend/videorenderbackend.h | 2 +- app/widget/viewer/viewer.cpp | 2 +- 7 files changed, 59 insertions(+), 27 deletions(-) diff --git a/app/render/backend/audiorenderbackend.cpp b/app/render/backend/audiorenderbackend.cpp index 9e819c0c8..368d70195 100644 --- a/app/render/backend/audiorenderbackend.cpp +++ b/app/render/backend/audiorenderbackend.cpp @@ -124,7 +124,7 @@ TimeRange AudioRenderBackend::PopNextFrameFromQueue() return range; } -void AudioRenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range) +void AudioRenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) { if (!ic_from_conform_) { // Cancel any ranges waiting on a conform here since obviously the contents have changed @@ -153,7 +153,7 @@ void AudioRenderBackend::InvalidateCacheInternal(const rational &start_range, co } } - RenderBackend::InvalidateCacheInternal(start_range, end_range); + RenderBackend::InvalidateCacheInternal(start_range, end_range, only_visible); } void AudioRenderBackend::ListenForConformSignal(AudioStreamPtr s) diff --git a/app/render/backend/audiorenderbackend.h b/app/render/backend/audiorenderbackend.h index ef6e6a090..6c6dd04f2 100644 --- a/app/render/backend/audiorenderbackend.h +++ b/app/render/backend/audiorenderbackend.h @@ -67,7 +67,7 @@ protected: virtual TimeRange PopNextFrameFromQueue() override; - virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range) override; + virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) override; private: struct ConformWaitInfo { diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index 8a4acb21e..cf0e92d87 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -290,24 +290,14 @@ void RenderBackend::CancelQueue() cancel_dialog_->RunIfWorkersAreBusy(); } +void RenderBackend::InvalidateVisible(const TimeRange &range, NodeInput *from) +{ + InvalidateCacheVeryInternal(range, from, true); +} + void RenderBackend::InvalidateCache(const TimeRange &range, NodeInput *from) { - // Adjust range to min/max values - rational start_range_adj = qMax(rational(0), range.in()); - rational end_range_adj = qMin(GetSequenceLength(), range.out()); - - qDebug() << "Cache invalidated between" - << start_range_adj.toDouble() - << "and" - << end_range_adj.toDouble(); - - if (from) { - // Queue value update - qDebug() << " from" << from->parentNode()->id() << "::" << from->id(); - QueueValueUpdate(from); - } - - InvalidateCacheInternal(start_range_adj, end_range_adj); + InvalidateCacheVeryInternal(range, from, false); } bool RenderBackend::ViewerIsConnected() const @@ -349,6 +339,26 @@ void RenderBackend::SetWorkerBusyState(RenderWorker *worker, bool busy) processor_busy_state_.replace(processors_.indexOf(worker), busy); } +void RenderBackend::InvalidateCacheVeryInternal(const TimeRange &range, NodeInput *from, bool only_visible) +{ + // Adjust range to min/max values + rational start_range_adj = qMax(rational(0), range.in()); + rational end_range_adj = qMin(GetSequenceLength(), range.out()); + + qDebug() << "Cache invalidated between" + << start_range_adj.toDouble() + << "and" + << end_range_adj.toDouble(); + + if (from) { + // Queue value update + qDebug() << " from" << from->parentNode()->id() << "::" << from->id(); + QueueValueUpdate(from); + } + + InvalidateCacheInternal(start_range_adj, end_range_adj, only_visible); +} + void RenderBackend::CopyNodeInputValue(NodeInput *input) { // Find our copy of this parameter @@ -446,8 +456,10 @@ const QVector &RenderBackend::threads() return threads_; } -void RenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range) +void RenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) { + Q_UNUSED(only_visible) + // Add the range to the list cache_queue_.InsertTimeRange(TimeRange(start_range, end_range)); diff --git a/app/render/backend/renderbackend.h b/app/render/backend/renderbackend.h index 1431d00df..90ecd9d6a 100644 --- a/app/render/backend/renderbackend.h +++ b/app/render/backend/renderbackend.h @@ -51,6 +51,8 @@ public: void CancelQueue(); + void InvalidateVisible(const TimeRange &range, NodeInput *from); + public slots: void InvalidateCache(const TimeRange &range, NodeInput *from); @@ -77,7 +79,7 @@ protected: */ virtual bool GenerateCacheIDInternal(QCryptographicHash& hash) = 0; - virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range); + virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible); virtual void CacheIDChangedEvent(const QString& id); @@ -120,6 +122,8 @@ protected: NodeGraph copied_graph_; private: + void InvalidateCacheVeryInternal(const TimeRange &range, NodeInput *from, bool only_visible); + void CopyNodeInputValue(NodeInput* input); Node *CopyNodeConnections(Node *src_node); void CopyNodeMakeConnection(NodeInput *src_input, NodeInput *dst_input); diff --git a/app/render/backend/videorenderbackend.cpp b/app/render/backend/videorenderbackend.cpp index db61fc0da..25ae78ce9 100644 --- a/app/render/backend/videorenderbackend.cpp +++ b/app/render/backend/videorenderbackend.cpp @@ -152,7 +152,7 @@ void VideoRenderBackend::ConnectWorkerToThis(RenderWorker *processor) connect(video_processor, &VideoRenderWorker::GeneratedFrame, this, &VideoRenderBackend::ThreadGeneratedFrame, Qt::QueuedConnection); } -void VideoRenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range) +void VideoRenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) { TimeRange invalidated(start_range, end_range); @@ -160,7 +160,21 @@ void VideoRenderBackend::InvalidateCacheInternal(const rational &start_range, co emit RangeInvalidated(invalidated); - Requeue(); + if (only_visible) { + + // We're only caching this frame, and for maximum responsiveness, should cancel the rest of the + // queue + cache_queue_.clear(); + cache_queue_.InsertTimeRange(TimeRange(start_range, end_range)); + + CacheNext(); + + } else { + + // Rework the queue + Requeue(); + + } } VideoRenderFrameCache *VideoRenderBackend::frame_cache() @@ -201,9 +215,11 @@ QString VideoRenderBackend::GetCachedFrame(const rational &time) void VideoRenderBackend::UpdateLastRequestedTime(const rational &time) { - last_time_requested_ = time; + if (last_time_requested_ != time) { + last_time_requested_ = time; - Requeue(); + Requeue(); + } } NodeInput *VideoRenderBackend::GetDependentInput() diff --git a/app/render/backend/videorenderbackend.h b/app/render/backend/videorenderbackend.h index fe7bc6f1b..401770ea9 100644 --- a/app/render/backend/videorenderbackend.h +++ b/app/render/backend/videorenderbackend.h @@ -99,7 +99,7 @@ protected: virtual void ConnectWorkerToThis(RenderWorker* processor) override; - virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range) override; + virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) override; virtual void ParamsChangedEvent(){} diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 8fd2bab3a..80908f563 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -878,7 +878,7 @@ void ViewerWidget::SetZoomFromMenu(QAction *action) void ViewerWidget::InvalidateVisible(NodeInput* source) { - video_renderer_->InvalidateCache(TimeRange(GetTime(), GetTime()), source); + video_renderer_->InvalidateVisible(TimeRange(GetTime(), GetTime()), source); } OLIVE_NAMESPACE_EXIT From 373eeaeacdbfa17dfc8681a5c2cbf9bf939dd139 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 01:29:05 +1000 Subject: [PATCH 4/8] renderer: when invalidating visible, kick the workers into emit mode --- app/render/backend/renderbackend.cpp | 7 +++++++ app/render/backend/renderbackend.h | 2 ++ app/render/backend/videorenderbackend.cpp | 21 ++++++++++++++++++++- app/render/backend/videorenderbackend.h | 4 ++++ app/widget/viewer/viewer.cpp | 8 ++++++++ app/widget/viewer/viewer.h | 2 ++ 6 files changed, 43 insertions(+), 1 deletion(-) diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index cf0e92d87..502f35916 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -259,6 +259,8 @@ void RenderBackend::CacheNext() SetWorkerBusyState(worker, true); cancel_dialog_->WorkerStarted(); + WorkerAboutToStartEvent(worker); + QMetaObject::invokeMethod(worker, "Render", Qt::QueuedConnection, @@ -471,6 +473,11 @@ void RenderBackend::CacheIDChangedEvent(const QString &id) Q_UNUSED(id) } +void RenderBackend::WorkerAboutToStartEvent(RenderWorker *worker) +{ + Q_UNUSED(worker) +} + void RenderBackend::InitWorkers() { for (int i=0;i(worker)-> + SetOperatingMode(static_cast(mode)); + } +} + VideoRenderFrameCache *VideoRenderBackend::frame_cache() { return &frame_cache_; diff --git a/app/render/backend/videorenderbackend.h b/app/render/backend/videorenderbackend.h index 401770ea9..97b1f09f9 100644 --- a/app/render/backend/videorenderbackend.h +++ b/app/render/backend/videorenderbackend.h @@ -103,6 +103,8 @@ protected: virtual void ParamsChangedEvent(){} + virtual void WorkerAboutToStartEvent(RenderWorker* worker) override; + VideoRenderWorker::OperatingMode operating_mode_; signals: @@ -135,6 +137,8 @@ private: bool pop_toggle_; + bool queue_is_visible_only_; + private slots: void ThreadCompletedDownload(NodeDependency dep, qint64 job_time, QByteArray hash); void ThreadSkippedFrame(NodeDependency dep, qint64 job_time, QByteArray hash); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 80908f563..292d07cc0 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -105,6 +105,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, this, &ViewerWidget::RendererCachedTime); connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, ruler(), &TimeRuler::CacheTimeReady); connect(video_renderer_, &VideoRenderBackend::RangeInvalidated, ruler(), &TimeRuler::CacheInvalidatedRange); + connect(video_renderer_, &VideoRenderBackend::GeneratedFrame, this, &ViewerWidget::RendererGeneratedFrame); audio_renderer_ = new AudioBackend(this); waveform_view_->SetBackend(audio_renderer_); @@ -522,6 +523,13 @@ void ViewerWidget::ContextMenuScopeTriggered(QAction *action) emit RequestScopePanel(static_cast(action->data().toInt())); } +void ViewerWidget::RendererGeneratedFrame(FramePtr f) +{ + foreach (ViewerDisplayWidget* glw, gl_widgets_) { + glw->SetImageFromLoadBuffer(f.get()); + } +} + void ViewerWidget::UpdateRendererParameters() { if (!GetConnectedNode()) { diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 6d22e89a8..afeeaadd0 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -236,6 +236,8 @@ private slots: void ContextMenuScopeTriggered(QAction* action); + void RendererGeneratedFrame(FramePtr f); + }; OLIVE_NAMESPACE_EXIT From 0f306550bf19e09c9d74f5139e58555055032f09 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 03:04:40 +1000 Subject: [PATCH 5/8] slider: use custom dragging code on mac The slider dragging implementation used for other platforms caused issues on macOS. We now have a custom Mac implementation that doesn't cause problems, and is arguably better than the other implementation anyway. --- app/CMakeLists.txt | 6 ++++ app/widget/slider/sliderlabel.cpp | 50 ++++++++++++++++++++----------- app/widget/slider/sliderlabel.h | 2 ++ 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b22b69ced..2bcbd2de3 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -155,6 +155,12 @@ if (WIN32) PRIVATE DbgHelp ) +elseif (APPLE) + target_link_libraries( + ${OLIVE_TARGET} + PRIVATE + "-framework ApplicationServices" + ) endif() set(OLIVE_TS_FILES diff --git a/app/widget/slider/sliderlabel.cpp b/app/widget/slider/sliderlabel.cpp index a54a54cf0..aee4a8409 100644 --- a/app/widget/slider/sliderlabel.cpp +++ b/app/widget/slider/sliderlabel.cpp @@ -22,6 +22,11 @@ #include #include +#include + +#ifdef Q_OS_MAC +#include +#endif OLIVE_NAMESPACE_ENTER @@ -48,40 +53,51 @@ SliderLabel::SliderLabel(QWidget *parent) : setFocusPolicy(Qt::TabFocus); } -void SliderLabel::mousePressEvent(QMouseEvent *ev) +void SliderLabel::mousePressEvent(QMouseEvent *) { - QLabel::mousePressEvent(ev); + emit drag_start(); +#if defined(Q_OS_MAC) + CGAssociateMouseAndMouseCursorPosition(false); + CGDisplayHideCursor(kCGDirectMainDisplay); + CGGetLastMouseDelta(nullptr, nullptr); +#else drag_start_ = QCursor::pos(); static_cast(QApplication::instance())->setOverrideCursor(Qt::BlankCursor); - - emit drag_start(); +#endif } -void SliderLabel::mouseMoveEvent(QMouseEvent *ev) +void SliderLabel::mouseMoveEvent(QMouseEvent *) { - QLabel::mouseMoveEvent(ev); - - QPoint current_pos = QCursor::pos(); - - int x_mvmt = current_pos.x() - drag_start_.x(); - int y_mvmt = drag_start_.y() - current_pos.y(); - - emit dragged(x_mvmt + y_mvmt); + int32_t x_mvmt, y_mvmt; // Keep cursor in the same position +#if defined(Q_OS_MAC) + CGGetLastMouseDelta(&x_mvmt, &y_mvmt); +#else + QPoint current_pos = QCursor::pos(); + + x_mvmt = current_pos.x() - drag_start_.x(); + y_mvmt = drag_start_.y() - current_pos.y(); + QCursor::setPos(drag_start_); +#endif + + emit dragged(x_mvmt + y_mvmt); } -void SliderLabel::mouseReleaseEvent(QMouseEvent *ev) +void SliderLabel::mouseReleaseEvent(QMouseEvent *) { - QWidget::mouseReleaseEvent(ev); +#if defined(Q_OS_MAC) + CGAssociateMouseAndMouseCursorPosition(true); + CGDisplayShowCursor(kCGDirectMainDisplay); +#else + static_cast(QApplication::instance())->restoreOverrideCursor(); +#endif // Emit a clicked signal emit drag_stop(); - - static_cast(QApplication::instance())->restoreOverrideCursor(); } void SliderLabel::focusInEvent(QFocusEvent *event) diff --git a/app/widget/slider/sliderlabel.h b/app/widget/slider/sliderlabel.h index 92771e669..c83e86bfc 100644 --- a/app/widget/slider/sliderlabel.h +++ b/app/widget/slider/sliderlabel.h @@ -54,6 +54,8 @@ signals: private: QPoint drag_start_; + bool cancel_mm_event_; + }; OLIVE_NAMESPACE_EXIT From 3da9643da2c142c6535dfb2cfbf4e68cc76aeeea Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 03:19:25 +1000 Subject: [PATCH 6/8] Squashed commit of the following: commit 8e06ded5769a41294d1f6645b1442634d2f503ff Author: itsmattkc Date: Thu May 7 03:18:39 2020 +1000 updated widget layout consistency commit ba0ef33d56af23ccb611bc10293bd6cd0a52f250 Merge: 0f306550 9a4f7b54 Author: itsmattkc Date: Thu May 7 03:12:12 2020 +1000 Merge branch 'pp_tabs' of https://github.com/ThomasWilshaw/olive into ThomasWilshaw-pp_tabs commit 9a4f7b546eb096c64de16ab6ea9d942963ac9ae2 Author: Thomas Wilshaw Date: Mon May 4 23:56:26 2020 +0100 Tabify Project Properties Move the project properites from boxes to tabs. --- .../projectproperties/projectproperties.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index e8dc50195..7f90d2bd2 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -44,10 +44,12 @@ ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : setWindowTitle(tr("Project Properties for '%1'").arg(working_project_->name())); + QTabWidget* tabs = new QTabWidget; + layout->addWidget(tabs); + { // Color management group - QGroupBox* color_group = new QGroupBox(); - color_group->setTitle(tr("Color Management")); + QWidget* color_group = new QWidget(); QGridLayout* color_layout = new QGridLayout(color_group); @@ -72,18 +74,19 @@ ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : color_layout->addWidget(browse_btn, 0, 2); connect(browse_btn, &QPushButton::clicked, this, &ProjectPropertiesDialog::BrowseForOCIOConfig); - layout->addWidget(color_group); - ocio_filename_->setText(working_project_->color_manager()->GetConfigFilename()); connect(ocio_filename_, &QLineEdit::textChanged, this, &ProjectPropertiesDialog::OCIOFilenameUpdated); OCIOFilenameUpdated(); + + tabs->addTab(color_group, tr("Color Management")); } + + { // Paths group - QGroupBox* paths_group = new QGroupBox(); - paths_group->setTitle(tr("Paths")); + QWidget* paths_group = new QWidget(); QGridLayout* paths_layout = new QGridLayout(paths_group); @@ -104,7 +107,7 @@ ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : paths_layout->addWidget(proxy_path_->browse_btn(), row, 2); paths_layout->addWidget(proxy_path_->default_box(), row, 3); - layout->addWidget(paths_group); + tabs->addTab(paths_group, tr("Paths")); } QDialogButtonBox* dialog_btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, From 3600d1254ddcdad74d6d4a263c3dd93e920e8c02 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 04:06:03 +1000 Subject: [PATCH 7/8] config: shorten default cache length --- app/config/config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/config.cpp b/app/config/config.cpp index c6e26a454..e3024ee18 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -98,8 +98,8 @@ void Config::SetDefaults() config_map_["DiskCachePath"] = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); config_map_["DiskCacheSize"] = 20.0; - config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(2)); - config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(10)); + config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(1)); + config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(5)); config_map_["ClearDiskCacheOnClose"] = false; config_map_["DefaultSequenceWidth"] = 1920; From e45256f6abc3ec80fe39a41ae5942b7150d752aa Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 04:56:34 +1000 Subject: [PATCH 8/8] cmake: rdynamic needs to be a *link* flag (not a compile flag) --- app/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 162256626..4998e2a99 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -111,7 +111,7 @@ else() endif() if(UNIX AND NOT APPLE) - target_compile_options( + target_link_options( ${OLIVE_TARGET} PRIVATE -rdynamic