diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index d438dc135..35a818bc0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -35,7 +35,6 @@ add_subdirectory(panel) add_subdirectory(render) add_subdirectory(shaders) add_subdirectory(task) -add_subdirectory(threading) add_subdirectory(timeline) add_subdirectory(ts) add_subdirectory(tool) @@ -99,7 +98,7 @@ if (WIN32) # Set Windows application icon target_sources(olive-editor PRIVATE packaging/windows/resources.rc) - # Preserve folder structure in visual studio + # Preserve folder structure in visual studio source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${OLIVE_SOURCES}) elseif(APPLE) diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt index 8a37e1776..d8a9a9a22 100644 --- a/app/render/CMakeLists.txt +++ b/app/render/CMakeLists.txt @@ -46,8 +46,6 @@ set(OLIVE_SOURCES render/renderer.cpp render/renderer.h render/rendercache.h - render/rendererthreadwrapper.cpp - render/rendererthreadwrapper.h render/renderjobtracker.cpp render/renderjobtracker.h render/rendermanager.cpp @@ -55,6 +53,8 @@ set(OLIVE_SOURCES render/rendermodes.h render/renderprocessor.cpp render/renderprocessor.h + render/renderticket.cpp + render/renderticket.h render/shadercode.h render/subtitleparams.cpp render/subtitleparams.h diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index e27dc2cf7..d5707c845 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -61,7 +61,7 @@ PreviewAutoCacher::~PreviewAutoCacher() SetViewerNode(nullptr); } -RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t, RenderTicketPriority priority) +RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t) { // If we have a single frame render queued (but not yet sent to the RenderManager), cancel it now CancelQueuedSingleFrameRender(); @@ -70,7 +70,6 @@ RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t, RenderTicke auto sfr = std::make_shared(); sfr->Start(); sfr->setProperty("time", QVariant::fromValue(t)); - sfr->setProperty("priority", int(priority)); // Queue it and try to render single_frame_render_ = sfr; @@ -79,9 +78,9 @@ RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t, RenderTicke return sfr; } -RenderTicketPtr PreviewAutoCacher::GetRangeOfAudio(TimeRange range, RenderTicketPriority priority) +RenderTicketPtr PreviewAutoCacher::GetRangeOfAudio(TimeRange range) { - return RenderAudio(range, false, priority); + return RenderAudio(range, false); } void PreviewAutoCacher::VideoInvalidated(const TimeRange &range) @@ -567,7 +566,6 @@ void PreviewAutoCacher::TryRender() if (single_frame_render_) { // Check if already caching this RenderTicketWatcher *watcher = RenderFrame(single_frame_render_->property("time").value(), - RenderTicketPriority(single_frame_render_->property("priority").toInt()), nullptr); video_immediate_passthroughs_[watcher].append(single_frame_render_); @@ -585,7 +583,7 @@ void PreviewAutoCacher::TryRender() // We want this hash, if we're not already rendering, start render now if (!render_task) { // Don't render any hash more than once - RenderFrame(t, RenderTicketPriority::kNormal, viewer_node_->video_frame_cache()); + RenderFrame(t, viewer_node_->video_frame_cache()); } emit SignalCacheProxyTaskProgress(double(queued_frame_iterator_.frame_index()) / double(queued_frame_iterator_.size())); @@ -605,13 +603,13 @@ void PreviewAutoCacher::TryRender() r.set_out(qMin(r.out(), r.in() + AudioVisualWaveform::kMinimumSampleRate.flipped())); // Start job - RenderAudio(r, true, RenderTicketPriority::kNormal); + RenderAudio(r, true); audio_iterator_.remove(r); } } -RenderTicketWatcher* PreviewAutoCacher::RenderFrame(Node *node, const rational& time, RenderTicketPriority priority, FrameHashCache *cache) +RenderTicketWatcher* PreviewAutoCacher::RenderFrame(Node *node, const rational& time, FrameHashCache *cache) { RenderTicketWatcher* watcher = new RenderTicketWatcher(); watcher->setProperty("job", QVariant::fromValue(last_update_time_)); @@ -625,19 +623,18 @@ RenderTicketWatcher* PreviewAutoCacher::RenderFrame(Node *node, const rational& time, RenderMode::kOffline, cache, - priority, RenderManager::kTexture)); return watcher; } -RenderTicketPtr PreviewAutoCacher::RenderAudio(Node *node, const TimeRange &r, bool generate_waveforms, RenderTicketPriority priority) +RenderTicketPtr PreviewAutoCacher::RenderAudio(Node *node, const TimeRange &r, bool generate_waveforms) { RenderTicketWatcher* watcher = new RenderTicketWatcher(); watcher->setProperty("job", QVariant::fromValue(last_update_time_)); connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::AudioRendered); audio_tasks_.insert(watcher, r); - RenderTicketPtr ticket = RenderManager::instance()->RenderAudio(node, r, copied_viewer_node_->GetAudioParams(), RenderMode::kOffline, generate_waveforms, priority); + RenderTicketPtr ticket = RenderManager::instance()->RenderAudio(node, r, copied_viewer_node_->GetAudioParams(), RenderMode::kOffline, generate_waveforms); watcher->SetTicket(ticket); return ticket; } diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h index 4c20a72d6..c9343021f 100644 --- a/app/render/previewautocacher.h +++ b/app/render/previewautocacher.h @@ -33,8 +33,6 @@ #include "render/audioparams.h" #include "render/renderjobtracker.h" #include "render/rendermanager.h" -#include "threading/threadpool.h" -#include "threading/threadticketwatcher.h" namespace olive { @@ -51,9 +49,9 @@ public: virtual ~PreviewAutoCacher() override; - RenderTicketPtr GetSingleFrame(const rational& t, RenderTicketPriority prioritize); + RenderTicketPtr GetSingleFrame(const rational& t); - RenderTicketPtr GetRangeOfAudio(TimeRange range, RenderTicketPriority prioritize); + RenderTicketPtr GetRangeOfAudio(TimeRange range); /** * @brief Set the viewer node to auto-cache @@ -100,16 +98,16 @@ signals: private: void TryRender(); - RenderTicketWatcher *RenderFrame(Node *node, const rational &time, RenderTicketPriority priority, FrameHashCache *cache); - RenderTicketWatcher *RenderFrame(const rational &time, RenderTicketPriority priority, FrameHashCache *cache) + RenderTicketWatcher *RenderFrame(Node *node, const rational &time, FrameHashCache *cache); + RenderTicketWatcher *RenderFrame(const rational &time, FrameHashCache *cache) { - return RenderFrame(copied_viewer_node_->GetConnectedTextureOutput(), time, priority, cache); + return RenderFrame(copied_viewer_node_->GetConnectedTextureOutput(), time, cache); } - RenderTicketPtr RenderAudio(Node *node, const TimeRange &range, bool generate_waveforms, RenderTicketPriority priority); - RenderTicketPtr RenderAudio(const TimeRange &range, bool generate_waveforms, RenderTicketPriority priority) + RenderTicketPtr RenderAudio(Node *node, const TimeRange &range, bool generate_waveforms); + RenderTicketPtr RenderAudio(const TimeRange &range, bool generate_waveforms) { - return RenderAudio(copied_viewer_node_->GetConnectedSampleOutput(), range, generate_waveforms, priority); + return RenderAudio(copied_viewer_node_->GetConnectedSampleOutput(), range, generate_waveforms); } /** diff --git a/app/render/rendererthreadwrapper.cpp b/app/render/rendererthreadwrapper.cpp deleted file mode 100644 index 50abd8b77..000000000 --- a/app/render/rendererthreadwrapper.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2022 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "rendererthreadwrapper.h" - -namespace olive { - -RendererThreadWrapper::RendererThreadWrapper(Renderer *inner, QObject *parent) : - Renderer(parent), - inner_(inner), - thread_(nullptr) -{ -} - -bool RendererThreadWrapper::Init() -{ - // Init context in main thread - if (!inner_->Init()) { - return false; - } - - // Create thread - thread_ = new QThread(this); - thread_->start(QThread::IdlePriority); - - // Move context to thread - inner_->moveToThread(thread_); - - // Queue post-init in new thread - QMetaObject::invokeMethod(inner_, "PostInit", Qt::BlockingQueuedConnection); - - return true; -} - -void RendererThreadWrapper::PostInit() -{ - // Do nothing -} - -void RendererThreadWrapper::DestroyInternal() -{ - if (thread_) { - QMetaObject::invokeMethod(inner_, "DestroyInternal", Qt::BlockingQueuedConnection); - - thread_->quit(); - thread_->wait(); - delete thread_; - thread_ = nullptr; - - // Destroy in main thread - inner_->PostDestroy(); - } -} - -void RendererThreadWrapper::ClearDestination(Texture *texture, double r, double g, double b, double a) -{ - QMetaObject::invokeMethod(inner_, "ClearDestination", Qt::BlockingQueuedConnection, - OLIVE_NS_ARG(Texture*, texture), - Q_ARG(double, r), - Q_ARG(double, g), - Q_ARG(double, b), - Q_ARG(double, a)); -} - -QVariant RendererThreadWrapper::CreateNativeTexture2D(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize) -{ - QVariant v; - - QMetaObject::invokeMethod(inner_, "CreateNativeTexture2D", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, v), - Q_ARG(int, width), - Q_ARG(int, height), - OLIVE_NS_ARG(VideoParams::Format, format), - Q_ARG(int, channel_count), - Q_ARG(const void*, data), - Q_ARG(int, linesize)); - - return v; -} - -QVariant RendererThreadWrapper::CreateNativeTexture3D(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize) -{ - QVariant v; - - QMetaObject::invokeMethod(inner_, "CreateNativeTexture3D", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, v), - Q_ARG(int, width), - Q_ARG(int, height), - Q_ARG(int, depth), - OLIVE_NS_ARG(VideoParams::Format, format), - Q_ARG(int, channel_count), - Q_ARG(const void*, data), - Q_ARG(int, linesize)); - - return v; -} - -void RendererThreadWrapper::DestroyNativeTexture(QVariant texture) -{ - QMetaObject::invokeMethod(inner_, "DestroyNativeTexture", Qt::BlockingQueuedConnection, - Q_ARG(QVariant, texture)); -} - -QVariant RendererThreadWrapper::CreateNativeShader(ShaderCode code) -{ - QVariant v; - - QMetaObject::invokeMethod(inner_, "CreateNativeShader", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, v), - OLIVE_NS_ARG(ShaderCode, code)); - - return v; -} - -void RendererThreadWrapper::DestroyNativeShader(QVariant shader) -{ - QMetaObject::invokeMethod(inner_, "DestroyNativeShader", Qt::BlockingQueuedConnection, - Q_ARG(QVariant, shader)); -} - -void RendererThreadWrapper::UploadToTexture(Texture *texture, const void *data, int linesize) -{ - QMetaObject::invokeMethod(inner_, "UploadToTexture", Qt::BlockingQueuedConnection, - OLIVE_NS_ARG(Texture*, texture), - Q_ARG(const void*, data), - Q_ARG(int, linesize)); -} - -void RendererThreadWrapper::DownloadFromTexture(Texture *texture, void *data, int linesize) -{ - QMetaObject::invokeMethod(inner_, "DownloadFromTexture", Qt::BlockingQueuedConnection, - OLIVE_NS_ARG(Texture*, texture), - Q_ARG(void*, data), - Q_ARG(int, linesize)); -} - -void RendererThreadWrapper::Flush() -{ - QMetaObject::invokeMethod(inner_, "Flush", Qt::BlockingQueuedConnection); -} - -Color RendererThreadWrapper::GetPixelFromTexture(Texture *texture, const QPointF &pt) -{ - Color c; - - QMetaObject::invokeMethod(inner_, "GetPixelFromTexture", Qt::BlockingQueuedConnection, - OLIVE_NS_RETURN_ARG(Color, c), - OLIVE_NS_ARG(Texture*, texture), - Q_ARG(QPointF, pt)); - - return c; -} - -void RendererThreadWrapper::Blit(QVariant shader, ShaderJob job, Texture *destination, VideoParams destination_params, bool clear_destination) -{ - QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection, - Q_ARG(QVariant, shader), - OLIVE_NS_ARG(ShaderJob, job), - OLIVE_NS_ARG(Texture*, destination), - OLIVE_NS_ARG(VideoParams, destination_params), - Q_ARG(bool, clear_destination)); -} - -} diff --git a/app/render/rendererthreadwrapper.h b/app/render/rendererthreadwrapper.h deleted file mode 100644 index 873e43832..000000000 --- a/app/render/rendererthreadwrapper.h +++ /dev/null @@ -1,86 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2022 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef RENDERCONTEXTTHREADWRAPPER_H -#define RENDERCONTEXTTHREADWRAPPER_H - -#include - -#include "renderer.h" - -namespace olive { - -class RendererThreadWrapper : public Renderer -{ -public: - RendererThreadWrapper(Renderer* inner, QObject* parent = nullptr); - - virtual ~RendererThreadWrapper() override - { - Destroy(); - PostDestroy(); - delete inner_; - } - - virtual bool Init() override; - - virtual void PostDestroy() override {} - -public slots: - virtual void PostInit() override; - - virtual void DestroyInternal() override; - - virtual void ClearDestination(olive::Texture *texture = nullptr, double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override; - - virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; - virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; - - virtual void DestroyNativeTexture(QVariant texture) override; - - virtual QVariant CreateNativeShader(olive::ShaderCode code) override; - - virtual void DestroyNativeShader(QVariant shader) override; - - virtual void UploadToTexture(olive::Texture* texture, const void* data, int linesize) override; - - virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) override; - - virtual void Flush() override; - - virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) override; - -protected slots: - virtual void Blit(QVariant shader, - olive::ShaderJob job, - olive::Texture* destination, - olive::VideoParams destination_params, - bool clear_destination) override; - -private: - Renderer* inner_; - - QThread* thread_; - -}; - -} - -#endif // RENDERCONTEXTTHREADWRAPPER_H diff --git a/app/render/rendermanager.cpp b/app/render/rendermanager.cpp index 2c4be2b1b..202820be5 100644 --- a/app/render/rendermanager.cpp +++ b/app/render/rendermanager.cpp @@ -27,7 +27,6 @@ #include "config/config.h" #include "core.h" #include "render/opengl/openglrenderer.h" -#include "render/rendererthreadwrapper.h" #include "renderprocessor.h" #include "task/conform/conform.h" #include "task/taskmanager.h" @@ -84,7 +83,7 @@ RenderManager::~RenderManager() RenderTicketPtr RenderManager::RenderFrame(Node *node, const VideoParams &vparam, const AudioParams ¶m, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, - FrameHashCache* cache, RenderTicketPriority priority, ReturnType return_type) + FrameHashCache* cache, ReturnType return_type) { return RenderFrame(node, color_manager, @@ -97,7 +96,6 @@ RenderTicketPtr RenderManager::RenderFrame(Node *node, const VideoParams &vparam VideoParams::kFormatInvalid, nullptr, cache, - priority, return_type); } @@ -107,7 +105,7 @@ RenderTicketPtr RenderManager::RenderFrame(Node *node, ColorManager* color_manag const QSize& force_size, const QMatrix4x4& force_matrix, VideoParams::Format force_format, ColorProcessorPtr force_color_output, - FrameHashCache* cache, RenderTicketPriority priority, ReturnType return_type) + FrameHashCache* cache, ReturnType return_type) { // Create ticket RenderTicketPtr ticket = std::make_shared(); @@ -136,7 +134,7 @@ RenderTicketPtr RenderManager::RenderFrame(Node *node, ColorManager* color_manag return ticket; } -RenderTicketPtr RenderManager::RenderAudio(Node *node, const TimeRange &r, const AudioParams ¶ms, RenderMode::Mode mode, bool generate_waveforms, RenderTicketPriority priority) +RenderTicketPtr RenderManager::RenderAudio(Node *node, const TimeRange &r, const AudioParams ¶ms, RenderMode::Mode mode, bool generate_waveforms) { // Create ticket RenderTicketPtr ticket = std::make_shared(); diff --git a/app/render/rendermanager.h b/app/render/rendermanager.h index 3100915df..a75c58aaf 100644 --- a/app/render/rendermanager.h +++ b/app/render/rendermanager.h @@ -30,8 +30,8 @@ #include "node/output/viewer/viewer.h" #include "node/traverser.h" #include "render/renderer.h" +#include "render/renderticket.h" #include "rendercache.h" -#include "threading/threadpool.h" namespace olive { @@ -110,14 +110,14 @@ public: */ RenderTicketPtr RenderFrame(Node *node, const VideoParams &vparam, const AudioParams ¶m, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, - FrameHashCache* cache = nullptr, RenderTicketPriority priority = RenderTicketPriority::kNormal, ReturnType return_type = kFrame); + FrameHashCache* cache = nullptr, ReturnType return_type = kFrame); RenderTicketPtr RenderFrame(Node *node, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, const VideoParams& video_params, const AudioParams& audio_params, const QSize& force_size, const QMatrix4x4& force_matrix, VideoParams::Format force_format, ColorProcessorPtr force_color_output, - FrameHashCache* cache = nullptr, RenderTicketPriority priority = RenderTicketPriority::kNormal, ReturnType return_type = kFrame); + FrameHashCache* cache = nullptr, ReturnType return_type = kFrame); /** * @brief Asynchronously generate a chunk of audio @@ -126,7 +126,7 @@ public: * * This function is thread-safe. */ - RenderTicketPtr RenderAudio(Node *viewer, const TimeRange& r, const AudioParams& params, RenderMode::Mode mode, bool generate_waveforms, RenderTicketPriority priority = RenderTicketPriority::kNormal); + RenderTicketPtr RenderAudio(Node *viewer, const TimeRange& r, const AudioParams& params, RenderMode::Mode mode, bool generate_waveforms); bool RemoveTicket(RenderTicketPtr ticket); diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index f0ef31227..73e871880 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -25,7 +25,7 @@ #include "node/traverser.h" #include "render/renderer.h" #include "rendercache.h" -#include "threading/threadticket.h" +#include "renderticket.h" namespace olive { diff --git a/app/threading/threadticket.cpp b/app/render/renderticket.cpp similarity index 61% rename from app/threading/threadticket.cpp rename to app/render/renderticket.cpp index 8f9715424..beba8b808 100644 --- a/app/threading/threadticket.cpp +++ b/app/render/renderticket.cpp @@ -18,7 +18,7 @@ ***/ -#include "threadticket.h" +#include "renderticket.h" namespace olive { @@ -128,4 +128,82 @@ void RenderTicket::FinishInternal(bool has_result, QVariant result) } } +RenderTicketWatcher::RenderTicketWatcher(QObject *parent) : + QObject(parent), + ticket_(nullptr) +{ +} + +void RenderTicketWatcher::SetTicket(RenderTicketPtr ticket) +{ + if (ticket_) { + qCritical() << "Tried to set a ticket on a RenderTicketWatcher twice"; + return; + } + + if (!ticket) { + qCritical() << "Tried to set a null ticket on a RenderTicketWatcher"; + return; + } + + ticket_ = ticket; + + // Lock ticket so we can query if it's already finished by the time this code runs + QMutexLocker locker(ticket->lock()); + + connect(ticket_.get(), &RenderTicket::Finished, this, &RenderTicketWatcher::TicketFinished); + + if (!ticket_->IsRunning(false) && ticket_->GetFinishCount(false) > 0) { + // Ticket has already finished before, so we emit a signal + locker.unlock(); + TicketFinished(); + } +} + +bool RenderTicketWatcher::IsRunning() +{ + if (ticket_) { + return ticket_->IsRunning(); + } else { + return false; + } +} + +void RenderTicketWatcher::WaitForFinished() +{ + if (ticket_) { + ticket_->WaitForFinished(); + } +} + +QVariant RenderTicketWatcher::Get() +{ + if (ticket_) { + return ticket_->Get(); + } else { + return QVariant(); + } +} + +bool RenderTicketWatcher::HasResult() +{ + if (ticket_) { + return ticket_->HasResult(); + } else { + return false; + } +} + +void RenderTicketWatcher::Cancel() +{ + if (ticket_) { + ticket_->Cancel(); + } +} + +void RenderTicketWatcher::TicketFinished() +{ + emit Finished(this); +} + } diff --git a/app/threading/threadticket.h b/app/render/renderticket.h similarity index 87% rename from app/threading/threadticket.h rename to app/render/renderticket.h index fb42ab969..700053653 100644 --- a/app/threading/threadticket.h +++ b/app/render/renderticket.h @@ -132,6 +132,40 @@ private: using RenderTicketPtr = std::shared_ptr; +class RenderTicketWatcher : public QObject +{ + Q_OBJECT +public: + RenderTicketWatcher(QObject* parent = nullptr); + + RenderTicketPtr GetTicket() const + { + return ticket_; + } + + void SetTicket(RenderTicketPtr ticket); + + bool IsRunning(); + + void WaitForFinished(); + + QVariant Get(); + + bool HasResult(); + + void Cancel(); + +signals: + void Finished(RenderTicketWatcher* watcher); + +private: + RenderTicketPtr ticket_; + +private slots: + void TicketFinished(); + +}; + } Q_DECLARE_METATYPE(olive::RenderTicketPtr) diff --git a/app/task/render/render.h b/app/task/render/render.h index d08c6d018..2609bc3d9 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -27,8 +27,7 @@ #include "node/color/colormanager/colormanager.h" #include "node/output/viewer/viewer.h" #include "task/task.h" -#include "threading/threadticket.h" -#include "threading/threadticketwatcher.h" +#include "render/renderticket.h" namespace olive { diff --git a/app/threading/CMakeLists.txt b/app/threading/CMakeLists.txt deleted file mode 100644 index ada17c49c..000000000 --- a/app/threading/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Olive - Non-Linear Video Editor -# Copyright (C) 2022 Olive Team -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -set(OLIVE_SOURCES - ${OLIVE_SOURCES} - threading/threadticket.cpp - threading/threadticket.h - threading/threadticketwatcher.cpp - threading/threadticketwatcher.h - threading/threadpool.cpp - threading/threadpool.h - PARENT_SCOPE -) diff --git a/app/threading/threadpool.cpp b/app/threading/threadpool.cpp deleted file mode 100644 index d65f6c574..000000000 --- a/app/threading/threadpool.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2022 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "threadpool.h" - -namespace olive { - -ThreadPool::ThreadPool(unsigned threads, QObject *parent) : - QObject(parent) -{ - if (threads == 0) { - threads = std::thread::hardware_concurrency(); - } - - for (unsigned i = 0; i < threads; i += 1) { - worker_threads_.emplace_back(std::bind(&ThreadPool::thread_exec, this, &tasks_, &task_mutex_, &cond_)); - } - - // Make single reserved thread for high priority tasks (usually audio) so they don't get stuck - // behind a lot of slow tasks - high_thread_ = std::thread(std::thread(std::bind(&ThreadPool::thread_exec, this, &high_tasks_, &high_mutex_, &high_cond_))); -} - -void ThreadPool::AddTicket(RenderTicketPtr ticket, RenderTicketPriority priority) -{ - if (priority == RenderTicketPriority::kHigh) { - std::lock_guard lock(high_mutex_); - high_tasks_.emplace_back(std::move(ticket)); - high_cond_.notify_one(); - } else { - std::lock_guard lock(task_mutex_); - tasks_.emplace_back(std::move(ticket)); - cond_.notify_one(); - } -} - -bool ThreadPool::RemoveTicket(RenderTicketPtr ticket) -{ - { - std::lock_guard lock(task_mutex_); - const auto it = std::find(tasks_.begin(), tasks_.end(), ticket); - if (it != tasks_.end()) { - tasks_.erase(it); - return true; - } - } - - { - std::lock_guard lock(high_mutex_); - const auto it = std::find(high_tasks_.begin(), high_tasks_.end(), ticket); - if (it != high_tasks_.end()) { - high_tasks_.erase(it); - return true; - } - } - - return false; -} - -void ThreadPool::thread_exec(std::deque *queue, std::mutex *mutex, std::condition_variable *cond) -{ - while (true) { - TaskType task; - - { - std::unique_lock lock(*mutex); - cond->wait(lock, [this, queue]{ return this->end_threadp_ || !queue->empty(); }); - - if (this->end_threadp_ && queue->empty()) { - break; - } - - task = std::move(queue->front()); - queue->pop_front(); - } - - RunTicket(task); - } -} - -ThreadPool::~ThreadPool() -{ - end_threadp_ = true; - cond_.notify_all(); - high_cond_.notify_all(); - - for (auto &e : worker_threads_) { - e.join(); - } - high_thread_.join(); -} - -} diff --git a/app/threading/threadpool.h b/app/threading/threadpool.h deleted file mode 100644 index e4dcb18e1..000000000 --- a/app/threading/threadpool.h +++ /dev/null @@ -1,70 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2022 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef THREADPOOL_H -#define THREADPOOL_H - -#include "threading/threadticket.h" - -#include -#include -#include -#include -#include - -namespace olive { - -enum class RenderTicketPriority { kHigh = 0, kNormal }; - -class ThreadPool : public QObject -{ - Q_OBJECT -public: - using TaskType = RenderTicketPtr; - ThreadPool(unsigned threads, QObject *parent); - - DISABLE_COPY_MOVE(ThreadPool) - - virtual void RunTicket(RenderTicketPtr ticket) const = 0; - void AddTicket(RenderTicketPtr ticket, RenderTicketPriority priority = RenderTicketPriority::kNormal); - bool RemoveTicket(RenderTicketPtr ticket); - - virtual ~ThreadPool() override; - -private: - void thread_exec(std::deque *queue, std::mutex *mutex, std::condition_variable *cond); - - std::vector worker_threads_; - std::deque tasks_; - std::mutex task_mutex_; - std::condition_variable cond_; - - std::thread high_thread_; - std::deque high_tasks_; - std::mutex high_mutex_; - std::condition_variable high_cond_; - - std::atomic_bool end_threadp_{false}; - -}; - -} // namespace olive - -#endif // THREADPOOL_H diff --git a/app/threading/threadticketwatcher.cpp b/app/threading/threadticketwatcher.cpp deleted file mode 100644 index a6ca5b2eb..000000000 --- a/app/threading/threadticketwatcher.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2022 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "threadticketwatcher.h" - -namespace olive { - -RenderTicketWatcher::RenderTicketWatcher(QObject *parent) : - QObject(parent), - ticket_(nullptr) -{ -} - -void RenderTicketWatcher::SetTicket(RenderTicketPtr ticket) -{ - if (ticket_) { - qCritical() << "Tried to set a ticket on a RenderTicketWatcher twice"; - return; - } - - if (!ticket) { - qCritical() << "Tried to set a null ticket on a RenderTicketWatcher"; - return; - } - - ticket_ = ticket; - - // Lock ticket so we can query if it's already finished by the time this code runs - QMutexLocker locker(ticket->lock()); - - connect(ticket_.get(), &RenderTicket::Finished, this, &RenderTicketWatcher::TicketFinished); - - if (!ticket_->IsRunning(false) && ticket_->GetFinishCount(false) > 0) { - // Ticket has already finished before, so we emit a signal - locker.unlock(); - TicketFinished(); - } -} - -bool RenderTicketWatcher::IsRunning() -{ - if (ticket_) { - return ticket_->IsRunning(); - } else { - return false; - } -} - -void RenderTicketWatcher::WaitForFinished() -{ - if (ticket_) { - ticket_->WaitForFinished(); - } -} - -QVariant RenderTicketWatcher::Get() -{ - if (ticket_) { - return ticket_->Get(); - } else { - return QVariant(); - } -} - -bool RenderTicketWatcher::HasResult() -{ - if (ticket_) { - return ticket_->HasResult(); - } else { - return false; - } -} - -void RenderTicketWatcher::Cancel() -{ - if (ticket_) { - ticket_->Cancel(); - } -} - -void RenderTicketWatcher::TicketFinished() -{ - emit Finished(this); -} - -} diff --git a/app/threading/threadticketwatcher.h b/app/threading/threadticketwatcher.h deleted file mode 100644 index 3b442e03e..000000000 --- a/app/threading/threadticketwatcher.h +++ /dev/null @@ -1,64 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2022 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef RENDERTICKETWATCHER_H -#define RENDERTICKETWATCHER_H - -#include "threadticket.h" - -namespace olive { - -class RenderTicketWatcher : public QObject -{ - Q_OBJECT -public: - RenderTicketWatcher(QObject* parent = nullptr); - - RenderTicketPtr GetTicket() const - { - return ticket_; - } - - void SetTicket(RenderTicketPtr ticket); - - bool IsRunning(); - - void WaitForFinished(); - - QVariant Get(); - - bool HasResult(); - - void Cancel(); - -signals: - void Finished(RenderTicketWatcher* watcher); - -private: - RenderTicketPtr ticket_; - -private slots: - void TicketFinished(); - -}; - -} - -#endif // RENDERTICKETWATCHER_H diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index dedca355c..f9bf5a8e0 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -578,7 +578,7 @@ void ViewerWidget::QueueNextAudioBuffer() RenderTicketWatcher *watcher = new RenderTicketWatcher(this); connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForPlayback); audio_playback_queue_.push_back(watcher); - watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(audio_playback_queue_time_, queue_end), RenderTicketPriority::kHigh)); + watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(audio_playback_queue_time_, queue_end))); audio_playback_queue_time_ = queue_end; } @@ -735,7 +735,7 @@ void ViewerWidget::UpdateTextureFromNode() ClearVideoAutoCacherQueue(); } - watcher->SetTicket(GetFrame(time, RenderTicketPriority::kNormal)); + watcher->SetTicket(GetFrame(time)); } else { // There is definitely no frame here, we can immediately flip to showing nothing nonqueue_watchers_.clear(); @@ -889,7 +889,7 @@ void ViewerWidget::PushScrubbedAudio() RenderTicketWatcher *watcher = new RenderTicketWatcher(); connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForScrubbing); - watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval), RenderTicketPriority::kHigh)); + watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval))); } } } @@ -939,7 +939,7 @@ void ViewerWidget::SetDisplayImage(QVariant frame) } } -RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(RenderTicketPriority priority, bool increment) +RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(bool increment) { RenderTicketWatcher *watcher = nullptr; @@ -955,19 +955,19 @@ RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(RenderTicketPriority watcher->setProperty("time", QVariant::fromValue(next_time)); connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue); queue_watchers_.append(watcher); - watcher->SetTicket(GetFrame(next_time, priority)); + watcher->SetTicket(GetFrame(next_time)); } return watcher; } -RenderTicketPtr ViewerWidget::GetFrame(const rational &t, RenderTicketPriority priority) +RenderTicketPtr ViewerWidget::GetFrame(const rational &t) { QString cache_fn = GetConnectedNode()->video_frame_cache()->GetValidCacheFilename(t); if (!QFileInfo::exists(cache_fn)) { // Frame hasn't been cached, start render job - return auto_cacher_.GetSingleFrame(t, priority); + return auto_cacher_.GetSingleFrame(t); } else { // Frame has been cached, grab the frame RenderTicketPtr ticket = std::make_shared(); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index ebb5c7ba5..d38ef5316 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -34,7 +34,6 @@ #include "node/output/viewer/viewer.h" #include "render/previewaudiodevice.h" #include "render/previewautocacher.h" -#include "threading/threadticketwatcher.h" #include "viewerdisplay.h" #include "viewersizer.h" #include "viewerwindow.h" @@ -202,9 +201,9 @@ private: void SetDisplayImage(QVariant frame); - RenderTicketWatcher *RequestNextFrameForQueue(RenderTicketPriority priority = RenderTicketPriority::kNormal, bool increment = true); + RenderTicketWatcher *RequestNextFrameForQueue(bool increment = true); - RenderTicketPtr GetFrame(const rational& t, RenderTicketPriority priority); + RenderTicketPtr GetFrame(const rational& t); void FinishPlayPreprocess();