From 46855adea768b409d01444f8e854dae57242d84d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 22 Dec 2019 03:03:08 +1100 Subject: [PATCH] use a system of deferred maps to keep track of frames that don't need to be rendered twice Mostly used for exporting to ensure all frames get accounted for when being sent from the renderer to the exporter through signals/slots. --- app/render/backend/opengl/openglworker.cpp | 2 -- app/render/backend/videorenderbackend.cpp | 38 ++++++++++---------- app/render/backend/videorenderframecache.cpp | 21 ++++++++--- app/render/backend/videorenderframecache.h | 5 +-- app/render/backend/videorenderworker.cpp | 2 +- 5 files changed, 39 insertions(+), 29 deletions(-) diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp index b3e3c5fc1..eaed586f4 100644 --- a/app/render/backend/opengl/openglworker.cpp +++ b/app/render/backend/opengl/openglworker.cpp @@ -45,8 +45,6 @@ bool OpenGLWorker::InitInternal() ctx_->moveToThread(this->thread()); - //qDebug() << "Processor initialized in thread" << thread() << "- context is in" << ctx_->thread(); - // The rest of the initialization needs to occur in the other thread, so we signal for it to start QMetaObject::invokeMethod(this, "FinishInit", Qt::QueuedConnection); diff --git a/app/render/backend/videorenderbackend.cpp b/app/render/backend/videorenderbackend.cpp index 1299f1f78..dcc911955 100644 --- a/app/render/backend/videorenderbackend.cpp +++ b/app/render/backend/videorenderbackend.cpp @@ -27,6 +27,7 @@ #include #include +#include "common/timecodefunctions.h" #include "render/pixelservice.h" #include "videorenderworker.h" @@ -55,12 +56,10 @@ void VideoRenderBackend::InvalidateCache(const rational &start_range, const rati << end_range_adj.toDouble(); // Snap start_range to timebase - double start_range_dbl = start_range_adj.toDouble(); - double start_range_numf = start_range_dbl * static_cast(params_.time_base().denominator()); - int64_t start_range_numround = qFloor(start_range_numf/static_cast(params_.time_base().numerator())) * params_.time_base().numerator(); - rational true_start_range(start_range_numround, params_.time_base().denominator()); + int64_t timestamp = olive::time_to_timestamp(start_range_adj, params_.time_base()); + rational true_start = olive::timestamp_to_time(timestamp, params_.time_base()); - for (rational r=true_start_range;r<=end_range_adj;r+=params_.time_base()) { + for (rational r=true_start;r times_with_this_hash = frame_cache()->DeferredMapsWithHash(hash); + foreach (const rational& t, times_with_this_hash) { + EmitCachedFrameReady(t, texture); + } + } + } + if (!export_mode_) { if (texture.isNull()) { // No frame received, we set hash to an empty @@ -268,18 +279,6 @@ void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, QByteArray ha } } - // Check if this frame has changed once again, in which case we may not want to draw it (it'll look jittery to the user) - if (!TimeIsQueued(TimeRange(path.in(), path.in()))) { - EmitCachedFrameReady(path.in(), texture); - - if (export_mode_) { - QList times_with_this_hash = frame_cache()->TimesWithHash(hash); - foreach (const rational& t, times_with_this_hash) { - EmitCachedFrameReady(t, texture); - } - } - } - // Queue up a new frame for this worker CacheNext(); } @@ -287,17 +286,18 @@ void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, QByteArray ha void VideoRenderBackend::ThreadCompletedDownload(NodeDependency dep, QByteArray hash) { frame_cache()->SetHash(dep.in(), hash); + emit CachedTimeReady(dep.in()); // Emit for each frame that has this hash (some may have been added in ThreadSkippedFrame) - QList times_with_this_hash = frame_cache()->TimesWithHash(hash); + QList times_with_this_hash = frame_cache()->DeferredMapsWithHash(hash); foreach (const rational& t, times_with_this_hash) { + frame_cache()->SetHash(t, hash); emit CachedTimeReady(t); } } void VideoRenderBackend::ThreadSkippedFrame(NodeDependency dep, QByteArray hash) { - frame_cache()->SetHash(dep.in(), hash); SetWorkerBusyState(static_cast(sender()), false); // Queue up a new frame for this worker diff --git a/app/render/backend/videorenderframecache.cpp b/app/render/backend/videorenderframecache.cpp index 9de93623b..0056224e1 100644 --- a/app/render/backend/videorenderframecache.cpp +++ b/app/render/backend/videorenderframecache.cpp @@ -26,13 +26,15 @@ bool VideoRenderFrameCache::IsCaching(const QByteArray &hash) return is_caching; } -bool VideoRenderFrameCache::TryCache(const QByteArray &hash) +bool VideoRenderFrameCache::TryCache(const rational& time, const QByteArray &hash) { currently_caching_lock_.lock(); bool is_caching = currently_caching_list_.contains(hash); - if (!is_caching) { + if (is_caching) { + deferred_maps_.insert(time, hash); + } else { currently_caching_list_.append(hash); } @@ -80,18 +82,27 @@ void VideoRenderFrameCache::Truncate(const rational &time) } } -QList VideoRenderFrameCache::TimesWithHash(const QByteArray &hash) +QList VideoRenderFrameCache::DeferredMapsWithHash(const QByteArray &hash) { QList list; - QMap::const_iterator iterator; + currently_caching_lock_.lock(); - for (iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { + QMap::iterator iterator = deferred_maps_.begin(); + + while (iterator != deferred_maps_.end()) { if (iterator.value() == hash) { list.append(iterator.key()); + iterator = deferred_maps_.erase(iterator); + } else { + iterator++; } } + currently_caching_list_.removeOne(hash); + + currently_caching_lock_.unlock(); + return list; } diff --git a/app/render/backend/videorenderframecache.h b/app/render/backend/videorenderframecache.h index 74a40f286..c8d4cb382 100644 --- a/app/render/backend/videorenderframecache.h +++ b/app/render/backend/videorenderframecache.h @@ -23,7 +23,7 @@ public: /** * @brief Check if a frame is currently being cached, and if not reserve it */ - bool TryCache(const QByteArray& hash); + bool TryCache(const rational &time, const QByteArray& hash); /** * @brief Return the path of the cached image at this time @@ -39,12 +39,13 @@ public: void Truncate(const rational& time); - QList TimesWithHash(const QByteArray& hash); + QList DeferredMapsWithHash(const QByteArray& hash); private: void RemoveHashFromCurrentlyCaching(const QByteArray& hash); QMap time_hash_map_; + QMap deferred_maps_; QMutex currently_caching_lock_; QVector currently_caching_list_; diff --git a/app/render/backend/videorenderworker.cpp b/app/render/backend/videorenderworker.cpp index ee00ff8d9..3c670baef 100644 --- a/app/render/backend/videorenderworker.cpp +++ b/app/render/backend/videorenderworker.cpp @@ -30,7 +30,7 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path) if (frame_cache_->HasHash(hash)) { // We've already cached this hash, no need to continue emit HashAlreadyExists(path, hash); - } else if (frame_cache_->TryCache(hash)) { + } else if (frame_cache_->TryCache(path.in(), hash)) { // This hash is available for us to cache, start traversing graph value = ProcessNode(path);