diff --git a/app/dialog/preferences/tabs/preferencesdisktab.cpp b/app/dialog/preferences/tabs/preferencesdisktab.cpp index b62e6f965..ea167d0c9 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.cpp +++ b/app/dialog/preferences/tabs/preferencesdisktab.cpp @@ -102,12 +102,8 @@ bool PreferencesDiskTab::Validate() if (disk_cache_location_->text() != default_disk_cache_folder_->GetPath()) { // Disk cache location is changing - // Check if the user wants to move the cache here - if (QMessageBox::question(this, - tr("Disk Cache"), - tr("You've chosen to change the default disk cache location. This " - "will invalidate your current cache. Would you like to continue?"), - QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { + // Check if the user is okay with invalidating the current cache + if (!DiskManager::ShowDiskCacheChangeConfirmationDialog(this)) { return false; } diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index 8a1b61655..abddcc295 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -34,6 +34,7 @@ namespace OCIO = OCIO_NAMESPACE::v1; #include "config/config.h" #include "core.h" #include "render/colormanager.h" +#include "render/diskmanager.h" OLIVE_NAMESPACE_ENTER @@ -89,8 +90,6 @@ ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : color_outer_layout->addStretch(); } - - { // Cache group QWidget* cache_group = new QWidget(); @@ -148,9 +147,10 @@ void ProjectPropertiesDialog::accept() return; } + QString new_cache_path; + if (disk_cache_use_default_btn_->isChecked()) { - // Empty cache path means default - working_project_->set_cache_path(QString()); + // Keep new cache path empty, which means default } else if (disk_cache_store_alongside_project_btn_->isChecked()) { QMessageBox::information(this, QString(), tr("\"Store alignside project\" functionality not implemented yet")); return; @@ -166,7 +166,19 @@ void ProjectPropertiesDialog::accept() return; } - working_project_->set_cache_path(cache_path_->text()); + // Set new path to the text as entered + new_cache_path = cache_path_->text(); + } + + if (new_cache_path != working_project_->cache_path(false)) { + // Check if the user is okay with invalidating the current cache + if (!DiskManager::ShowDiskCacheChangeConfirmationDialog(this)) { + return; + } + + working_project_->set_cache_path(new_cache_path); + + emit DiskManager::instance()->InvalidateProject(working_project_); } // This should ripple changes throughout the program that the color config has changed, therefore must be done last @@ -210,7 +222,6 @@ void ProjectPropertiesDialog::OCIOFilenameUpdated() default_input_colorspace_->setCurrentIndex(default_input_colorspace_->count()-1); } } - } catch (OCIO::Exception& e) { ocio_config_is_valid_ = false; ocio_filename_->setStyleSheet(QStringLiteral("QLineEdit {color: red;}")); diff --git a/app/project/project.cpp b/app/project/project.cpp index 5b14774d9..fe1e307aa 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -26,6 +26,7 @@ #include "common/xmlutils.h" #include "core.h" #include "dialog/progress/progress.h" +#include "render/diskmanager.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER @@ -63,6 +64,10 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, const } } + } else if (reader->name() == QStringLiteral("cachepath")) { + + set_cache_path(reader->readElementText()); + } else if (reader->name() == QStringLiteral("layout")) { // Since the main window's functions have to occur in the GUI thread (and we're likely @@ -98,6 +103,8 @@ void Project::Save(QXmlStreamWriter *writer) const writer->writeTextElement("url", filename_); + writer->writeTextElement("cachepath", cache_path(false)); + root_.Save(writer); writer->writeStartElement("colormanagement"); @@ -195,4 +202,12 @@ bool Project::is_new() const return !is_modified_ && filename_.isEmpty(); } +const QString &Project::cache_path(bool default_if_empty) const +{ + if (cache_path_.isEmpty() && default_if_empty) { + return DiskManager::instance()->GetDefaultCachePath(); + } + return cache_path_; +} + OLIVE_NAMESPACE_EXIT diff --git a/app/project/project.h b/app/project/project.h index 2a806c29c..9fa99ce48 100644 --- a/app/project/project.h +++ b/app/project/project.h @@ -25,7 +25,6 @@ #include #include "render/colormanager.h" -#include "render/diskmanager.h" #include "project/item/folder/folder.h" #include "window/mainwindow/mainwindowlayoutinfo.h" @@ -72,14 +71,10 @@ public: bool is_new() const; - const QString& cache_path(bool default_if_empty = true) const { - if (cache_path_.isEmpty() && default_if_empty) { - return DiskManager::instance()->GetDefaultCachePath(); - } - return cache_path_; - } + const QString& cache_path(bool default_if_empty = true) const; - void set_cache_path(const QString& cache_path) { + void set_cache_path(const QString& cache_path) + { cache_path_ = cache_path; } diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index 3a1a78a34..e8ba9dabc 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -37,8 +37,6 @@ AudioPlaybackCache::AudioPlaybackCache(QObject* parent) : void AudioPlaybackCache::SetParameters(const AudioParams ¶ms) { - QMutexLocker locker(lock()); - if (params_ == params) { return; } @@ -52,22 +50,17 @@ void AudioPlaybackCache::SetParameters(const AudioParams ¶ms) } // Our current audio cache is unusable, so we truncate it automatically - TimeRange invalidate_range(0, NoLockGetLength()); + TimeRange invalidate_range(0, GetLength()); if (invalidate_range.in() != invalidate_range.out()) { - NoLockInvalidate(invalidate_range); + Invalidate(invalidate_range); } - locker.unlock(); - emit ParametersChanged(); - emit Invalidated(invalidate_range); } void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr samples, const qint64 &job_time) { - QMutexLocker locker(lock()); - - QList valid_ranges = NoLockGetValidRanges(range, job_time); + QList valid_ranges = GetValidRanges(range, job_time); if (valid_ranges.isEmpty()) { return; } @@ -102,11 +95,7 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr sample f.close(); - NoLockValidate(range); - - locker.unlock(); - - emit Validated(range); + Validate(range); } else { qWarning() << "Failed to write PCM data to" << filename_; } @@ -114,8 +103,6 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr sample void AudioPlaybackCache::WriteSilence(const TimeRange &range) { - QMutexLocker locker(lock()); - QFile f(filename_); if (f.open(QFile::ReadWrite)) { qint64 start_offset = params_.time_to_bytes(range.in()); @@ -132,6 +119,8 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range) f.write(a); f.close(); + + Validate(range); } else { qWarning() << "Failed to write PCM data to" << filename_; } @@ -232,7 +221,7 @@ void AudioPlaybackCache::LengthChangedEvent(const rational& old, const rational& } } -QList AudioPlaybackCache::NoLockGetValidRanges(const TimeRange& range, const qint64& job_time) +QList AudioPlaybackCache::GetValidRanges(const TimeRange& range, const qint64& job_time) { QList valid_ranges; diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index 5fdb224df..fe9c7cd6f 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -33,8 +33,8 @@ class AudioPlaybackCache : public PlaybackCache public: AudioPlaybackCache(QObject* parent = nullptr); - AudioParams GetParameters() { - QMutexLocker locker(lock()); + AudioParams GetParameters() + { return params_; } @@ -48,12 +48,7 @@ public: const QString& GetCacheFilename() const; - QList GetValidRanges(const TimeRange &range, const qint64 &job_time) - { - QMutexLocker locker(lock()); - - return NoLockGetValidRanges(range, job_time); - } + QList GetValidRanges(const TimeRange &range, const qint64 &job_time); signals: void ParametersChanged(); @@ -64,8 +59,6 @@ protected: virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; private: - QList NoLockGetValidRanges(const TimeRange &range, const qint64 &job_time); - void UpdateFilename(const QString& s); QString filename_; diff --git a/app/render/diskmanager.cpp b/app/render/diskmanager.cpp index 076bf0475..7194e63b6 100644 --- a/app/render/diskmanager.cpp +++ b/app/render/diskmanager.cpp @@ -136,6 +136,15 @@ DiskCacheFolder *DiskManager::GetOpenFolder(const QString &path) return f; } +bool DiskManager::ShowDiskCacheChangeConfirmationDialog(QWidget *parent) +{ + return (QMessageBox::question(parent, + tr("Disk Cache"), + tr("You've chosen to change the default disk cache location. This " + "will invalidate your current cache. Would you like to continue?"), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok); +} + DiskCacheFolder::DiskCacheFolder(const QString &path, QObject *parent) : QObject(parent) { diff --git a/app/render/diskmanager.h b/app/render/diskmanager.h index 551534c4f..9fc04cf7a 100644 --- a/app/render/diskmanager.h +++ b/app/render/diskmanager.h @@ -26,6 +26,7 @@ #include #include "common/define.h" +#include "project/project.h" OLIVE_NAMESPACE_ENTER @@ -128,6 +129,8 @@ public: return open_folders_; } + static bool ShowDiskCacheChangeConfirmationDialog(QWidget* parent); + public slots: void Accessed(const QString& cache_folder, const QByteArray& hash); @@ -136,6 +139,8 @@ public slots: signals: void DeletedFrame(const QString& path, const QByteArray& hash); + void InvalidateProject(Project* p); + private: DiskManager(); diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index f4e980446..7ed84d274 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -39,20 +39,17 @@ FrameHashCache::FrameHashCache(QObject *parent) : { if (DiskManager::instance()) { connect(DiskManager::instance(), &DiskManager::DeletedFrame, this, &FrameHashCache::HashDeleted); + connect(DiskManager::instance(), &DiskManager::InvalidateProject, this, &FrameHashCache::ProjectInvalidated); } } QByteArray FrameHashCache::GetHash(const rational &time) { - QMutexLocker locker(lock()); - return time_hash_map_.value(time); } void FrameHashCache::SetHash(const rational &time, const QByteArray &hash, const qint64& job_time, bool frame_exists) { - QMutexLocker locker(lock()); - bool is_current = false; for (int i=jobs_.size()-1; i>=0; i--) { @@ -74,54 +71,34 @@ void FrameHashCache::SetHash(const rational &time, const QByteArray &hash, const TimeRange validated_range; if (frame_exists) { validated_range = TimeRange(time, time + timebase_); - NoLockValidate(validated_range); - } - - locker.unlock(); - - if (frame_exists) { - emit Validated(validated_range); + Validate(validated_range); } } void FrameHashCache::SetTimebase(const rational &tb) { - QMutexLocker locker(lock()); - timebase_ = tb; } void FrameHashCache::ValidateFramesWithHash(const QByteArray &hash) { - QMutexLocker locker(lock()); - QMap::const_iterator iterator; - const TimeRangeList& invalidated_ranges = NoLockGetInvalidatedRanges(); - TimeRangeList ranges_validated; + const TimeRangeList& invalidated_ranges = GetInvalidatedRanges(); for (iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { if (iterator.value() == hash) { TimeRange frame_range(iterator.key(), iterator.key() + timebase_); if (invalidated_ranges.ContainsTimeRange(frame_range)) { - NoLockValidate(frame_range); - ranges_validated.InsertTimeRange(frame_range); + Validate(frame_range); } } } - - locker.unlock(); - - foreach (const TimeRange& range, ranges_validated) { - emit Validated(range); - } } QList FrameHashCache::GetFramesWithHash(const QByteArray &hash) { - QMutexLocker locker(lock()); - QList times; QMap::const_iterator iterator; @@ -137,8 +114,6 @@ QList FrameHashCache::GetFramesWithHash(const QByteArray &hash) QList FrameHashCache::TakeFramesWithHash(const QByteArray &hash) { - QMutexLocker locker(lock()); - QList times; QMap::iterator iterator = time_hash_map_.begin(); @@ -154,13 +129,7 @@ QList FrameHashCache::TakeFramesWithHash(const QByteArray &hash) } foreach (const rational& r, times) { - NoLockInvalidate(TimeRange(r, r + timebase_)); - } - - locker.unlock(); - - foreach (const rational& r, times) { - emit Invalidated(TimeRange(r, r + timebase_)); + Invalidate(TimeRange(r, r + timebase_)); } return times; @@ -168,8 +137,6 @@ QList FrameHashCache::TakeFramesWithHash(const QByteArray &hash) QMap FrameHashCache::time_hash_map() { - QMutexLocker locker(lock()); - return time_hash_map_; } @@ -205,23 +172,17 @@ QVector FrameHashCache::GetFrameListFromTimeRange(TimeRangeList range_ QVector FrameHashCache::GetFrameListFromTimeRange(const TimeRangeList &range) { - QMutexLocker locker(lock()); - return GetFrameListFromTimeRange(range, timebase_); } QVector FrameHashCache::GetInvalidatedFrames() { - QMutexLocker locker(lock()); - - return GetFrameListFromTimeRange(NoLockGetInvalidatedRanges(), timebase_); + return GetFrameListFromTimeRange(GetInvalidatedRanges()); } QVector FrameHashCache::GetInvalidatedFrames(const TimeRange &intersecting) { - QMutexLocker locker(lock()); - - return GetFrameListFromTimeRange(NoLockGetInvalidatedRanges().Intersects(intersecting), timebase_); + return GetFrameListFromTimeRange(GetInvalidatedRanges().Intersects(intersecting)); } bool FrameHashCache::SaveCacheFrame(const QByteArray& hash, @@ -379,24 +340,20 @@ void FrameHashCache::HashDeleted(const QString& s, const QByteArray &hash) return; } - QMutexLocker locker(lock()); - - TimeRangeList invalidated; - QMap::const_iterator i; for (i=time_hash_map_.constBegin(); i!=time_hash_map_.constEnd(); i++) { if (i.value() == hash) { - TimeRange r(i.key(), i.key() + timebase_); - - NoLockInvalidate(r); - invalidated.InsertTimeRange(r); + Invalidate(TimeRange(i.key(), i.key() + timebase_)); } } +} - locker.unlock(); +void FrameHashCache::ProjectInvalidated(Project *p) +{ + if (GetProject() == p) { + time_hash_map_.clear(); - foreach (const TimeRange& r, invalidated) { - emit Invalidated(r); + InvalidateAll(); } } diff --git a/app/render/framehashcache.h b/app/render/framehashcache.h index 5c6fe8c58..d3314e587 100644 --- a/app/render/framehashcache.h +++ b/app/render/framehashcache.h @@ -89,6 +89,8 @@ private: private slots: void HashDeleted(const QString &s, const QByteArray& hash); + void ProjectInvalidated(Project* p); + }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/playbackcache.cpp b/app/render/playbackcache.cpp index 3bde6ebe5..d791e4bd9 100644 --- a/app/render/playbackcache.cpp +++ b/app/render/playbackcache.cpp @@ -30,36 +30,30 @@ OLIVE_NAMESPACE_ENTER void PlaybackCache::Invalidate(const TimeRange &r) { - QMutexLocker locker(lock()); + Q_ASSERT(r.in() != r.out()); - NoLockInvalidate(r); + invalidated_.InsertTimeRange(r); - locker.unlock(); + RemoveRangeFromJobs(r); + qint64 job_time = QDateTime::currentMSecsSinceEpoch(); + jobs_.append({r, job_time}); + + InvalidateEvent(r); emit Invalidated(r); } void PlaybackCache::InvalidateAll() { - QMutexLocker locker(lock()); - if (length_.isNull()) { return; } - TimeRange invalidate_range(0, length_); - - NoLockInvalidate(invalidate_range); - - locker.unlock(); - - emit Invalidated(invalidate_range); + Invalidate(TimeRange(0, length_)); } void PlaybackCache::SetLength(const rational &r) { - QMutexLocker locker(lock()); - if (length_ == r) { // Same length - do nothing return; @@ -85,8 +79,6 @@ void PlaybackCache::SetLength(const rational &r) rational old_length = length_; length_ = r; - locker.unlock(); - if (r > old_length) { emit Invalidated(range_diff); } else { @@ -100,21 +92,19 @@ void PlaybackCache::Shift(const rational &from, const rational &to) return; } - QMutexLocker locker(lock()); - // An region between `from` and `to` will be inserted or spliced out TimeRangeList ranges_to_shift = invalidated_.Intersects(TimeRange(from, RATIONAL_MAX)); // Remove everything from the minimum point TimeRange remove_range = TimeRange(qMin(from, to), RATIONAL_MAX); - NoLockValidate(remove_range); RemoveRangeFromJobs(remove_range); + Validate(remove_range); // Shift everything in our ranges to shift list // (`diff` is POSITIVE when moving forward -> and NEGATIVE when moving backward <-) rational diff = to - from; foreach (const TimeRange& r, ranges_to_shift) { - NoLockInvalidate(r + diff); + Invalidate(r + diff); } ShiftEvent(from, to); @@ -123,38 +113,18 @@ void PlaybackCache::Shift(const rational &from, const rational &to) if (diff > rational()) { // If shifting forward, add this section to the invalidated region - NoLockInvalidate(TimeRange(from, to)); + Invalidate(TimeRange(from, to)); } - locker.unlock(); - // Emit signals - emit Validated(remove_range); - foreach (const TimeRange& r, ranges_to_shift) { - emit Invalidated(r + diff); - } - if (diff > rational()) { - emit Invalidated(TimeRange(from, to)); - } emit Shifted(from, to); } -void PlaybackCache::NoLockInvalidate(const TimeRange &r) -{ - Q_ASSERT(r.in() != r.out()); - - invalidated_.InsertTimeRange(r); - - RemoveRangeFromJobs(r); - qint64 job_time = QDateTime::currentMSecsSinceEpoch(); - jobs_.append({r, job_time}); - - InvalidateEvent(r); -} - -void PlaybackCache::NoLockValidate(const TimeRange &r) +void PlaybackCache::Validate(const TimeRange &r) { invalidated_.RemoveTimeRange(r); + + emit Validated(r); } void PlaybackCache::LengthChangedEvent(const rational &, const rational &) @@ -169,6 +139,22 @@ void PlaybackCache::ShiftEvent(const rational &, const rational &) { } +Project *PlaybackCache::GetProject() const +{ + // NOTE: A lot of assumptions in this behavior + ViewerOutput* viewer = static_cast(parent()); + if (!viewer) { + return nullptr; + } + + Sequence* sequence = static_cast(viewer->parent()); + if (!sequence) { + return nullptr; + } + + return sequence->project(); +} + void PlaybackCache::RemoveRangeFromJobs(const TimeRange &remove) { // Code shamelessly copied from TimeRangeList::RemoveTimeRange @@ -196,23 +182,13 @@ void PlaybackCache::RemoveRangeFromJobs(const TimeRange &remove) QString PlaybackCache::GetCacheDirectory() const { - // NOTE: A lot of assumptions in this behavior - ViewerOutput* viewer = static_cast(parent()); - if (!viewer) { + Project* project = GetProject(); + + if (project) { + return project->cache_path(); + } else { return QString(); } - - Sequence* sequence = static_cast(viewer->parent()); - if (!sequence) { - return QString(); - } - - Project* project = sequence->project(); - if (!project) { - return QString(); - } - - return project->cache_path(); } OLIVE_NAMESPACE_EXIT diff --git a/app/render/playbackcache.h b/app/render/playbackcache.h index 881476830..2f857d4c1 100644 --- a/app/render/playbackcache.h +++ b/app/render/playbackcache.h @@ -28,6 +28,8 @@ OLIVE_NAMESPACE_ENTER +class Project; + class PlaybackCache : public QObject { Q_OBJECT @@ -43,17 +45,13 @@ public: const rational& GetLength() { - QMutexLocker locker(lock()); - - return NoLockGetLength(); + return length_; } void SetLength(const rational& r); bool IsFullyValidated() { - QMutexLocker locker(lock()); - return invalidated_.isEmpty(); } @@ -61,15 +59,11 @@ public: const TimeRangeList& GetInvalidatedRanges() { - QMutexLocker locker(lock()); - - return NoLockGetInvalidatedRanges(); + return invalidated_; } bool HasInvalidatedRanges() { - QMutexLocker locker(lock()); - return !invalidated_.isEmpty(); } @@ -83,19 +77,7 @@ signals: void LengthChanged(const OLIVE_NAMESPACE::rational& r); protected: - void NoLockInvalidate(const TimeRange& r); - - void NoLockValidate(const TimeRange& r); - - const rational& NoLockGetLength() const - { - return length_; - } - - const TimeRangeList& NoLockGetInvalidatedRanges() - { - return invalidated_; - } + void Validate(const TimeRange& r); virtual void LengthChangedEvent(const rational& old, const rational& newlen); @@ -103,12 +85,9 @@ protected: virtual void ShiftEvent(const rational& from, const rational& to); - QString GetCacheDirectory() const; + Project* GetProject() const; - QMutex* lock() - { - return &lock_; - } + QString GetCacheDirectory() const; struct JobIdentifier { TimeRange range; @@ -120,8 +99,6 @@ protected: private: void RemoveRangeFromJobs(const TimeRange& remove); - QMutex lock_; - TimeRangeList invalidated_; rational length_;