cache: merged cachetask and footagecache into one precache task
Since the actual auto-cache now happens elsewhere, this cleans up a lot of dead code.
This commit is contained in:
@@ -51,7 +51,6 @@
|
||||
#include "render/diskmanager.h"
|
||||
#include "render/pixelformat.h"
|
||||
#include "render/shaderinfo.h"
|
||||
#include "task/cache/cache.h"
|
||||
#include "task/project/import/import.h"
|
||||
#include "task/project/load/load.h"
|
||||
#include "task/project/save/save.h"
|
||||
|
||||
@@ -464,8 +464,6 @@ void RenderBackend::TicketFinished()
|
||||
|
||||
void RenderBackend::WorkerGeneratedWaveform(RenderTicketPtr ticket, TrackOutput *track, AudioVisualWaveform samples, TimeRange range)
|
||||
{
|
||||
qDebug() << "Hello?";
|
||||
|
||||
QList<TimeRange> valid_ranges = viewer_node_->audio_playback_cache()->GetValidRanges(range,
|
||||
ticket->GetJobTime());
|
||||
if (!valid_ranges.isEmpty()) {
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
add_subdirectory(cache)
|
||||
add_subdirectory(conform)
|
||||
add_subdirectory(export)
|
||||
add_subdirectory(precache)
|
||||
add_subdirectory(project)
|
||||
add_subdirectory(render)
|
||||
|
||||
|
||||
Vendored
-53
@@ -1,53 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "footagecache.h"
|
||||
|
||||
#include "common/timecodefunctions.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
FootageCacheTask::FootageCacheTask(VideoStreamPtr footage, Sequence *sequence) :
|
||||
CacheTask(new ViewerOutput(), sequence->video_params(), sequence->audio_params(), false),
|
||||
footage_(footage)
|
||||
{
|
||||
viewer()->set_video_params(sequence->video_params());
|
||||
viewer()->set_audio_params(sequence->audio_params());
|
||||
backend()->SetVideoParams(sequence->video_params());
|
||||
backend()->SetAudioParams(sequence->audio_params());
|
||||
|
||||
video_node_ = new VideoInput();
|
||||
video_node_->SetFootage(footage);
|
||||
|
||||
NodeParam::ConnectEdge(video_node_->output(), viewer()->texture_input());
|
||||
|
||||
SetTitle(tr("Pre-caching %1:%2").arg(footage->footage()->filename(),
|
||||
QString::number(footage->index())));
|
||||
|
||||
backend()->ProcessUpdateQueue();
|
||||
}
|
||||
|
||||
FootageCacheTask::~FootageCacheTask()
|
||||
{
|
||||
delete viewer();
|
||||
delete video_node_;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
Vendored
-48
@@ -1,48 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef FOOTAGECACHETASK_H
|
||||
#define FOOTAGECACHETASK_H
|
||||
|
||||
#include "cache.h"
|
||||
#include "node/input/media/video/video.h"
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "project/item/sequence/sequence.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class FootageCacheTask : public CacheTask
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FootageCacheTask(VideoStreamPtr footage, Sequence* sequence);
|
||||
|
||||
virtual ~FootageCacheTask() override;
|
||||
|
||||
private:
|
||||
VideoStreamPtr footage_;
|
||||
|
||||
VideoInput* video_node_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // FOOTAGECACHETASK_H
|
||||
@@ -148,8 +148,10 @@ QFuture<void> ExportTask::DownloadFrame(FramePtr frame, const QByteArray &hash)
|
||||
return QtConcurrent::run(FrameColorConvert, color_processor_, frame);
|
||||
}
|
||||
|
||||
void ExportTask::FrameDownloaded(const QByteArray &hash, const std::list<rational> ×)
|
||||
void ExportTask::FrameDownloaded(const QByteArray &hash, const std::list<rational> ×, qint64 job_time)
|
||||
{
|
||||
Q_UNUSED(job_time)
|
||||
|
||||
FramePtr f = rendered_frame_.value(hash);
|
||||
|
||||
foreach (const rational& t, times) {
|
||||
@@ -173,8 +175,10 @@ void ExportTask::FrameDownloaded(const QByteArray &hash, const std::list<rationa
|
||||
}
|
||||
}
|
||||
|
||||
void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
|
||||
void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples, qint64 job_time)
|
||||
{
|
||||
Q_UNUSED(job_time)
|
||||
|
||||
TimeRange adjusted_range = range;
|
||||
|
||||
if (params_.has_custom_range()) {
|
||||
|
||||
@@ -40,9 +40,9 @@ protected:
|
||||
|
||||
virtual QFuture<void> DownloadFrame(FramePtr frame, const QByteArray &hash) override;
|
||||
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times) override;
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times, qint64 job_time) override;
|
||||
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples, qint64 job_time) override;
|
||||
|
||||
private:
|
||||
QHash<QByteArray, FramePtr> rendered_frame_;
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
task/cache/cache.h
|
||||
task/cache/cache.cpp
|
||||
task/cache/footagecache.h
|
||||
task/cache/footagecache.cpp
|
||||
task/precache/precachetask.h
|
||||
task/precache/precachetask.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -18,81 +18,80 @@
|
||||
|
||||
***/
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
#include <QLinkedList>
|
||||
#include <QMatrix4x4>
|
||||
|
||||
#include "project/item/sequence/sequence.h"
|
||||
#include "precachetask.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
CacheTask::CacheTask(RenderBackend *backend, bool in_out_only) :
|
||||
RenderTask(backend),
|
||||
in_out_only_(in_out_only)
|
||||
PreCacheTask::PreCacheTask(VideoStreamPtr footage, Sequence* sequence) :
|
||||
RenderTask(new ViewerOutput(), sequence->video_params(), sequence->audio_params()),
|
||||
footage_(footage)
|
||||
{
|
||||
Init();
|
||||
viewer()->set_video_params(sequence->video_params());
|
||||
viewer()->set_audio_params(sequence->audio_params());
|
||||
|
||||
// Render fastest quality
|
||||
backend()->SetRenderMode(RenderMode::kOffline);
|
||||
|
||||
video_node_ = new VideoInput();
|
||||
video_node_->SetFootage(footage);
|
||||
|
||||
NodeParam::ConnectEdge(video_node_->output(), viewer()->texture_input());
|
||||
|
||||
SetTitle(tr("Pre-caching %1:%2").arg(footage->footage()->filename(),
|
||||
QString::number(footage->index())));
|
||||
|
||||
backend()->NodeGraphChanged(viewer()->texture_input());
|
||||
backend()->ProcessUpdateQueue();
|
||||
}
|
||||
|
||||
CacheTask::CacheTask(ViewerOutput* viewer, const VideoParams& vparams, const AudioParams &aparams, bool in_out_only) :
|
||||
RenderTask(viewer, vparams, aparams),
|
||||
in_out_only_(in_out_only)
|
||||
PreCacheTask::~PreCacheTask()
|
||||
{
|
||||
Init();
|
||||
delete viewer();
|
||||
delete video_node_;
|
||||
}
|
||||
|
||||
bool CacheTask::Run()
|
||||
bool PreCacheTask::Run()
|
||||
{
|
||||
// Get list of invalidated ranges
|
||||
TimeRangeList video_range = viewer()->video_frame_cache()->GetInvalidatedRanges();
|
||||
TimeRangeList audio_range = viewer()->audio_playback_cache()->GetInvalidatedRanges();
|
||||
|
||||
// If we're caching only in-out, limit the range to that
|
||||
/*
|
||||
if (in_out_only_) {
|
||||
Sequence* s = static_cast<Sequence*>(viewer()->parent());
|
||||
|
||||
if (s->workarea()->enabled()) {
|
||||
video_range = video_range.Intersects(s->workarea()->range());
|
||||
audio_range = audio_range.Intersects(s->workarea()->range());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Render(video_range, audio_range, true);
|
||||
Render(video_range, TimeRangeList(), true);
|
||||
|
||||
download_threads_.waitForDone();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QFuture<void> CacheTask::DownloadFrame(FramePtr frame, const QByteArray &hash)
|
||||
QFuture<void> PreCacheTask::DownloadFrame(FramePtr frame, const QByteArray &hash)
|
||||
{
|
||||
return QtConcurrent::run(&download_threads_, FrameHashCache::SaveCacheFrame, hash, frame);
|
||||
}
|
||||
|
||||
void CacheTask::FrameDownloaded(const QByteArray &hash, const std::list<rational> ×)
|
||||
void PreCacheTask::FrameDownloaded(const QByteArray &hash, const std::list<rational> ×, qint64 job_time)
|
||||
{
|
||||
foreach (const rational& t, times) {
|
||||
viewer()->video_frame_cache()->SetHash(t, hash, job_time(), true);
|
||||
viewer()->video_frame_cache()->SetHash(t, hash, job_time, true);
|
||||
}
|
||||
}
|
||||
|
||||
void CacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
|
||||
void PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples, qint64 job_time)
|
||||
{
|
||||
if (samples) {
|
||||
viewer()->audio_playback_cache()->WritePCM(range, samples, job_time());
|
||||
} else {
|
||||
viewer()->audio_playback_cache()->WriteSilence(range);
|
||||
}
|
||||
}
|
||||
// Pre-cache doesn't cache any audio
|
||||
|
||||
void CacheTask::Init()
|
||||
{
|
||||
SetTitle(tr("Caching \"%1\"").arg(viewer()->media_name()));
|
||||
|
||||
backend()->EnablePreviewGeneration(job_time());
|
||||
|
||||
// Render fastest quality
|
||||
backend()->SetRenderMode(RenderMode::kOffline);
|
||||
Q_UNUSED(range)
|
||||
Q_UNUSED(samples)
|
||||
Q_UNUSED(job_time)
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -18,38 +18,36 @@
|
||||
|
||||
***/
|
||||
|
||||
#ifndef CACHETASK_H
|
||||
#define CACHETASK_H
|
||||
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#ifndef PRECACHETASK_H
|
||||
#define PRECACHETASK_H
|
||||
|
||||
#include "node/input/media/video/video.h"
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "project/item/sequence/sequence.h"
|
||||
#include "task/render/render.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class CacheTask : public RenderTask
|
||||
class PreCacheTask : public RenderTask
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CacheTask(RenderBackend* backend, bool in_out_only);
|
||||
CacheTask(ViewerOutput* viewer,
|
||||
const VideoParams &vparams,
|
||||
const AudioParams &aparams,
|
||||
bool in_out_only);
|
||||
PreCacheTask(VideoStreamPtr footage, Sequence* sequence);
|
||||
|
||||
virtual ~PreCacheTask() override;
|
||||
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
virtual QFuture<void> DownloadFrame(FramePtr frame, const QByteArray &hash) override;
|
||||
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times) override;
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times, qint64 job_time) override;
|
||||
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples, qint64 job_time) override;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
VideoStreamPtr footage_;
|
||||
|
||||
bool in_out_only_;
|
||||
VideoInput* video_node_;
|
||||
|
||||
QThreadPool download_threads_;
|
||||
|
||||
@@ -57,4 +55,4 @@ private:
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // CACHETASK_H
|
||||
#endif // PRECACHETASK_H
|
||||
+13
-30
@@ -24,31 +24,17 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
RenderTask::RenderTask(RenderBackend *backend) :
|
||||
backend_(backend)
|
||||
{
|
||||
job_time_ = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
backend_is_ours_ = false;
|
||||
}
|
||||
|
||||
RenderTask::RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams)
|
||||
{
|
||||
job_time_ = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
backend_ = new OpenGLBackend();
|
||||
backend_->SetViewerNode(viewer);
|
||||
backend_->SetVideoParams(vparams);
|
||||
backend_->SetAudioParams(aparams);
|
||||
|
||||
backend_is_ours_ = true;
|
||||
}
|
||||
|
||||
RenderTask::~RenderTask()
|
||||
{
|
||||
if (backend_is_ours_) {
|
||||
backend_->deleteLater();
|
||||
}
|
||||
delete backend_;
|
||||
}
|
||||
|
||||
struct TimeHashFuturePair {
|
||||
@@ -74,6 +60,7 @@ struct RangeSampleFuturePair {
|
||||
struct HashDownloadFuturePair {
|
||||
QByteArray hash;
|
||||
QFuture<void> download_future;
|
||||
qint64 job_time;
|
||||
};
|
||||
|
||||
void RenderTask::Render(const TimeRangeList& video_range,
|
||||
@@ -99,16 +86,16 @@ void RenderTask::Render(const TimeRangeList& video_range,
|
||||
QVector<rational> times;
|
||||
QVector<QByteArray> hashes;
|
||||
std::list<HashTimePair> frame_queue;
|
||||
qint64 hash_job_time;
|
||||
|
||||
if (!video_range.isEmpty()) {
|
||||
QList<QByteArray> existing_hashes;
|
||||
|
||||
times = viewer()->video_frame_cache()->GetFrameListFromTimeRange(video_range);
|
||||
|
||||
total_length += video_frame_sz * times.size();
|
||||
|
||||
RenderTicketPtr hash_future = backend_->Hash(times);
|
||||
hashes = hash_future->Get().value<QVector<QByteArray> >();
|
||||
hash_job_time = hash_future->GetJobTime();
|
||||
|
||||
if (!hash_future->WasCancelled()) {
|
||||
for (int i=0;i<times.size();i++) {
|
||||
@@ -136,6 +123,7 @@ void RenderTask::Render(const TimeRangeList& video_range,
|
||||
|| !audio_lookup_table.empty())) {
|
||||
|
||||
if (!IsCancelled() && !frame_queue.empty()) {
|
||||
|
||||
// Pop another frame off the frame queue
|
||||
const HashTimePair& p = frame_queue.front();
|
||||
|
||||
@@ -163,7 +151,7 @@ void RenderTask::Render(const TimeRangeList& video_range,
|
||||
|
||||
if (hash_exists) {
|
||||
// Already exists, no need to render it again
|
||||
FrameDownloaded(p.hash, {p.time});
|
||||
FrameDownloaded(p.hash, {p.time}, hash_job_time);
|
||||
progress_counter += video_frame_sz;
|
||||
emit ProgressChanged(progress_counter / total_length);
|
||||
}
|
||||
@@ -193,7 +181,7 @@ void RenderTask::Render(const TimeRangeList& video_range,
|
||||
FramePtr f = i->frame_future->Get().value<FramePtr>();
|
||||
|
||||
// Start multithreaded download here
|
||||
download_futures.push_back({i->hash, DownloadFrame(f, i->hash)});
|
||||
download_futures.push_back({i->hash, DownloadFrame(f, i->hash), i->frame_future->GetJobTime()});
|
||||
}
|
||||
|
||||
i = render_lookup_table.erase(i);
|
||||
@@ -215,7 +203,7 @@ void RenderTask::Render(const TimeRangeList& video_range,
|
||||
}
|
||||
}
|
||||
|
||||
FrameDownloaded(j->hash, times_with_hash);
|
||||
FrameDownloaded(j->hash, times_with_hash, j->job_time);
|
||||
|
||||
existing_hashes.push_back(j->hash);
|
||||
|
||||
@@ -234,7 +222,9 @@ void RenderTask::Render(const TimeRangeList& video_range,
|
||||
|
||||
while (!IsCancelled() && k != audio_lookup_table.end()) {
|
||||
if (k->sample_future->IsFinished()) {
|
||||
AudioDownloaded(k->range, k->sample_future->Get().value<SampleBufferPtr>());
|
||||
AudioDownloaded(k->range,
|
||||
k->sample_future->Get().value<SampleBufferPtr>(),
|
||||
k->sample_future->GetJobTime());
|
||||
|
||||
progress_counter += k->range.length().toDouble();
|
||||
emit ProgressChanged(progress_counter / total_length);
|
||||
@@ -246,15 +236,8 @@ void RenderTask::Render(const TimeRangeList& video_range,
|
||||
}
|
||||
}
|
||||
|
||||
if (backend_is_ours_) {
|
||||
// `Close` will block until all jobs are done making a safe deletion
|
||||
backend_->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTask::SetAnchorPoint(const rational &r)
|
||||
{
|
||||
anchor_point_ = r;
|
||||
// `Close` will block until all jobs are done making a safe deletion
|
||||
backend_->Close();
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -32,7 +32,6 @@ OLIVE_NAMESPACE_ENTER
|
||||
class RenderTask : public Task
|
||||
{
|
||||
public:
|
||||
RenderTask(RenderBackend* backend);
|
||||
RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams);
|
||||
|
||||
virtual ~RenderTask() override;
|
||||
@@ -44,9 +43,9 @@ protected:
|
||||
|
||||
virtual QFuture<void> DownloadFrame(FramePtr frame, const QByteArray &hash) = 0;
|
||||
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times) = 0;
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times, qint64 job_time) = 0;
|
||||
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0;
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples, qint64 job_time) = 0;
|
||||
|
||||
ViewerOutput* viewer() const
|
||||
{
|
||||
@@ -63,27 +62,14 @@ protected:
|
||||
return backend_->GetAudioParams();
|
||||
}
|
||||
|
||||
void SetAnchorPoint(const rational& r);
|
||||
|
||||
const qint64& job_time() const
|
||||
{
|
||||
return job_time_;
|
||||
}
|
||||
|
||||
RenderBackend* backend()
|
||||
{
|
||||
return backend_;
|
||||
}
|
||||
|
||||
private:
|
||||
rational anchor_point_;
|
||||
|
||||
RenderBackend* backend_;
|
||||
|
||||
bool backend_is_ours_;
|
||||
|
||||
qint64 job_time_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "core.h"
|
||||
#include "dialog/footageproperties/footageproperties.h"
|
||||
#include "dialog/sequence/sequence.h"
|
||||
#include "task/cache/footagecache.h"
|
||||
#include "task/precache/precachetask.h"
|
||||
#include "task/taskmanager.h"
|
||||
#include "widget/menu/menu.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
@@ -427,7 +427,7 @@ void ProjectExplorer::ContextMenuStartProxy(QAction *a)
|
||||
|
||||
// Start a background task for proxying
|
||||
foreach (VideoStreamPtr video_stream, video_streams) {
|
||||
FootageCacheTask* proxy_task = new FootageCacheTask(video_stream, sequence);
|
||||
PreCacheTask* proxy_task = new PreCacheTask(video_stream, sequence);
|
||||
TaskManager::instance()->AddTask(proxy_task);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ void TimelineViewBase::drawForeground(QPainter *painter, const QRectF &rect)
|
||||
|
||||
// Get playhead highlight color
|
||||
QColor highlight = palette().text().color();
|
||||
highlight.setAlpha(128);
|
||||
highlight.setAlpha(32);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(highlight);
|
||||
painter->drawRect(playhead_rect);
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "panel/scope/scope.h"
|
||||
#include "render/backend/opengl/openglbackend.h"
|
||||
#include "render/backend/renderticketwatcher.h"
|
||||
#include "task/cache/cache.h"
|
||||
#include "viewerdisplay.h"
|
||||
#include "viewerplaybacktimer.h"
|
||||
#include "viewerqueue.h"
|
||||
|
||||
Reference in New Issue
Block a user