some render cache adjustments
This commit is contained in:
@@ -91,3 +91,12 @@ bool NodeGraph::ContainsNode(Node *n)
|
||||
{
|
||||
return (n->parent() == this);
|
||||
}
|
||||
|
||||
void NodeGraph::Release()
|
||||
{
|
||||
QList<Node*> all_nodes = nodes();
|
||||
|
||||
foreach (Node* n, all_nodes) {
|
||||
n->Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,11 @@ public:
|
||||
*/
|
||||
bool ContainsNode(Node* n);
|
||||
|
||||
/**
|
||||
* @brief Releases all Nodes in this NodeGraph
|
||||
*/
|
||||
void Release();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when a Node is added to the graph
|
||||
|
||||
@@ -315,7 +315,6 @@ void Node::Hash(QCryptographicHash *hash, NodeOutput* from, const rational &time
|
||||
{
|
||||
// Add this Node's ID
|
||||
hash->addData(id().toUtf8());
|
||||
qDebug() << "Hashing" << id();
|
||||
|
||||
// Add each value
|
||||
QList<NodeParam*> params = parameters();
|
||||
|
||||
@@ -80,8 +80,10 @@ void ViewerOutput::AttachViewer(ViewerPanel *viewer)
|
||||
|
||||
void ViewerOutput::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
|
||||
{
|
||||
// Update any attached viewer
|
||||
UpdateViewer();
|
||||
if (start_range == current_time_ || end_range == current_time_) {
|
||||
// Update any attached viewer
|
||||
UpdateViewer();
|
||||
}
|
||||
|
||||
Node::InvalidateCache(start_range, end_range, from);
|
||||
}
|
||||
@@ -89,6 +91,7 @@ void ViewerOutput::InvalidateCache(const rational &start_range, const rational &
|
||||
void ViewerOutput::UpdateViewer()
|
||||
{
|
||||
texture_input_->ClearCachedValue();
|
||||
|
||||
ViewerTimeChanged(current_time_);
|
||||
}
|
||||
|
||||
|
||||
@@ -238,3 +238,8 @@ void NodeParam::ClearCachedValue()
|
||||
// currently cached
|
||||
time_ = -1;
|
||||
}
|
||||
|
||||
const rational &NodeParam::LastRequestedTime()
|
||||
{
|
||||
return time_;
|
||||
}
|
||||
|
||||
@@ -208,6 +208,11 @@ public:
|
||||
*/
|
||||
void ClearCachedValue();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the last time this parameter had a value requested from
|
||||
*/
|
||||
const rational& LastRequestedTime();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Signal emitted when an edge is added to this parameter
|
||||
|
||||
@@ -36,8 +36,7 @@ RendererProcessor::RendererProcessor() :
|
||||
width_(0),
|
||||
height_(0),
|
||||
divider_(1),
|
||||
caching_(false),
|
||||
last_requested_time_(-1)
|
||||
caching_(false)
|
||||
{
|
||||
texture_input_ = new NodeInput("tex_in");
|
||||
texture_input_->add_data_input(NodeInput::kTexture);
|
||||
@@ -79,8 +78,6 @@ void RendererProcessor::SetCacheName(const QString &s)
|
||||
QVariant RendererProcessor::Value(NodeOutput* output, const rational& time)
|
||||
{
|
||||
if (output == texture_output_) {
|
||||
last_requested_time_ = time;
|
||||
|
||||
if (!texture_input_->IsConnected()) {
|
||||
// Nothing is connected - nothing to show or render
|
||||
return 0;
|
||||
@@ -98,7 +95,6 @@ QVariant RendererProcessor::Value(NodeOutput* output, const rational& time)
|
||||
|
||||
// Find frame in map
|
||||
if (time_hash_map_.contains(time)) {
|
||||
qDebug() << "Showed:" << time_hash_map_[time].toHex();
|
||||
|
||||
QString fn = CachePathName(time_hash_map_[time]);
|
||||
|
||||
@@ -340,6 +336,11 @@ void RendererProcessor::ThreadCallback()
|
||||
|
||||
time_hash_map_.insert(cache_frame_, master_thread_->hash());
|
||||
|
||||
// We didn't receive a texture to download, but the viewer may still need updating
|
||||
if (texture == nullptr) {
|
||||
DownloadThreadFinished(cache_frame_);
|
||||
}
|
||||
|
||||
CacheNext();
|
||||
}
|
||||
}
|
||||
@@ -357,15 +358,15 @@ void RendererProcessor::ThreadRequestSibling(NodeDependency dep)
|
||||
void RendererProcessor::DownloadThreadFinished(const rational& time)
|
||||
{
|
||||
// Check if we just downloaded (akak finished caching) the frame we're currently on
|
||||
if (texture_output_->IsConnected() && time == last_requested_time_) {
|
||||
if (texture_output_->IsConnected()) {
|
||||
if (texture_output_->LastRequestedTime() == time) {
|
||||
texture_output_->ClearCachedValue();
|
||||
}
|
||||
|
||||
// Send invalidate cache signal to all nodes connected to the texture output
|
||||
QVector<NodeEdgePtr> edges = texture_output()->edges();
|
||||
|
||||
texture_output_->ClearCachedValue();
|
||||
|
||||
foreach (NodeEdgePtr edge, edges) {
|
||||
edge->input()->ClearCachedValue();
|
||||
|
||||
edge->input()->parent()->InvalidateCache(time,
|
||||
time,
|
||||
edge->input());
|
||||
|
||||
@@ -176,8 +176,6 @@ private:
|
||||
QVector<RendererDownloadThreadPtr> download_threads_;
|
||||
int last_download_thread_;
|
||||
|
||||
rational last_requested_time_;
|
||||
|
||||
RenderTexturePtr master_texture_;
|
||||
|
||||
QMap<rational, QByteArray> time_hash_map_;
|
||||
|
||||
@@ -12,7 +12,8 @@ RendererDownloadThread::RendererDownloadThread(QOpenGLContext *share_ctx,
|
||||
const int &height,
|
||||
const olive::PixelFormat &format,
|
||||
const olive::RenderMode &mode) :
|
||||
RendererThreadBase(share_ctx, width, height, format, mode)
|
||||
RendererThreadBase(share_ctx, width, height, format, mode),
|
||||
cancelled_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -29,6 +30,17 @@ void RendererDownloadThread::Queue(RenderTexturePtr texture, const QString& fn,
|
||||
texture_queue_lock_.unlock();
|
||||
}
|
||||
|
||||
void RendererDownloadThread::Cancel()
|
||||
{
|
||||
cancelled_ = true;
|
||||
|
||||
texture_queue_lock_.lock();
|
||||
wait_cond_.wakeAll();
|
||||
texture_queue_lock_.unlock();
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
void RendererDownloadThread::ProcessLoop()
|
||||
{
|
||||
QOpenGLFunctions* f = render_instance()->context()->functions();
|
||||
@@ -53,13 +65,21 @@ void RendererDownloadThread::ProcessLoop()
|
||||
OIIO::ImageSpec spec(render_instance()->width(), render_instance()->height(), kRGBAChannels, format_info.oiio_desc);
|
||||
spec.attribute("compression", "dwaa:200");
|
||||
|
||||
while (!Cancelled()) {
|
||||
while (!cancelled_) {
|
||||
// Check queue for textures to download (use mutex to prevent collisions)
|
||||
texture_queue_lock_.lock();
|
||||
|
||||
while (texture_queue_.isEmpty()) {
|
||||
// Main waiting condition
|
||||
wait_cond_.wait(&texture_queue_lock_);
|
||||
|
||||
if (cancelled_) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cancelled_) {
|
||||
texture_queue_lock_.unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
working_texture = texture_queue_.takeFirst();
|
||||
|
||||
@@ -15,6 +15,9 @@ public:
|
||||
|
||||
void Queue(RenderTexturePtr texture, const QString &fn, const rational &time);
|
||||
|
||||
public slots:
|
||||
virtual void Cancel() override;
|
||||
|
||||
signals:
|
||||
void Downloaded(const rational& time);
|
||||
|
||||
@@ -32,6 +35,8 @@ private:
|
||||
|
||||
QMutex texture_queue_lock_;
|
||||
|
||||
QAtomicInt cancelled_;
|
||||
|
||||
};
|
||||
|
||||
using RendererDownloadThreadPtr = std::shared_ptr<RendererDownloadThread>;
|
||||
|
||||
@@ -29,7 +29,8 @@ RendererProcessThread::RendererProcessThread(RendererProcessor* parent,
|
||||
const olive::PixelFormat &format,
|
||||
const olive::RenderMode &mode) :
|
||||
RendererThreadBase(share_ctx, width, height, format, mode),
|
||||
parent_(parent)
|
||||
parent_(parent),
|
||||
cancelled_(false)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -70,12 +71,27 @@ RenderTexturePtr RendererProcessThread::texture()
|
||||
return texture_;
|
||||
}
|
||||
|
||||
void RendererProcessThread::Cancel()
|
||||
{
|
||||
cancelled_ = true;
|
||||
|
||||
mutex_.lock();
|
||||
wait_cond_.wakeAll();
|
||||
mutex_.unlock();
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
void RendererProcessThread::ProcessLoop()
|
||||
{
|
||||
while (!Cancelled()) {
|
||||
while (!cancelled_) {
|
||||
// Main waiting condition
|
||||
wait_cond_.wait(&mutex_);
|
||||
|
||||
if (cancelled_) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Wake up main thread
|
||||
caller_mutex_.lock();
|
||||
wait_cond_.wakeAll();
|
||||
|
||||
@@ -42,6 +42,9 @@ public:
|
||||
|
||||
RenderTexturePtr texture();
|
||||
|
||||
public slots:
|
||||
virtual void Cancel() override;
|
||||
|
||||
protected:
|
||||
virtual void ProcessLoop() override;
|
||||
|
||||
@@ -61,6 +64,8 @@ private:
|
||||
|
||||
RenderTexturePtr texture_;
|
||||
|
||||
QAtomicInt cancelled_;
|
||||
|
||||
};
|
||||
|
||||
using RendererProcessThreadPtr = std::shared_ptr<RendererProcessThread>;
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
RendererThreadBase::RendererThreadBase(QOpenGLContext *share_ctx, const int &width, const int &height, const olive::PixelFormat &format, const olive::RenderMode &mode) :
|
||||
share_ctx_(share_ctx),
|
||||
cancelled_(false),
|
||||
width_(width),
|
||||
height_(height),
|
||||
format_(format),
|
||||
@@ -34,15 +33,6 @@ RendererThreadBase::RendererThreadBase(QOpenGLContext *share_ctx, const int &wid
|
||||
connect(share_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Cancel()));
|
||||
}
|
||||
|
||||
void RendererThreadBase::Cancel()
|
||||
{
|
||||
// Escape main loop
|
||||
cancelled_ = true;
|
||||
|
||||
// Wait until thread is finished before returning
|
||||
wait();
|
||||
}
|
||||
|
||||
RenderInstance *RendererThreadBase::render_instance()
|
||||
{
|
||||
return render_instance_;
|
||||
@@ -79,11 +69,6 @@ void RendererThreadBase::run()
|
||||
mutex_.unlock();
|
||||
}
|
||||
|
||||
bool RendererThreadBase::Cancelled()
|
||||
{
|
||||
return cancelled_;
|
||||
}
|
||||
|
||||
void RendererThreadBase::StartThread(QThread::Priority priority)
|
||||
{
|
||||
caller_mutex_.lock();
|
||||
|
||||
@@ -46,13 +46,11 @@ public:
|
||||
virtual void run() override;
|
||||
|
||||
public slots:
|
||||
void Cancel();
|
||||
virtual void Cancel() = 0;
|
||||
|
||||
protected:
|
||||
virtual void ProcessLoop() = 0;
|
||||
|
||||
bool Cancelled();
|
||||
|
||||
QWaitCondition wait_cond_;
|
||||
|
||||
QMutex mutex_;
|
||||
@@ -62,8 +60,6 @@ protected:
|
||||
private:
|
||||
QOpenGLContext* share_ctx_;
|
||||
|
||||
bool cancelled_;
|
||||
|
||||
const int& width_;
|
||||
|
||||
const int& height_;
|
||||
|
||||
@@ -25,7 +25,14 @@ PanelManager* olive::panel_focus_manager = nullptr;
|
||||
PanelManager::PanelManager(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void PanelManager::DeleteAllPanels()
|
||||
{
|
||||
foreach (PanelWidget* panel, focus_history_) {
|
||||
delete panel;
|
||||
}
|
||||
focus_history_.clear();
|
||||
}
|
||||
|
||||
PanelWidget *PanelManager::CurrentlyFocused() const
|
||||
|
||||
@@ -47,6 +47,8 @@ class PanelManager : public QObject
|
||||
public:
|
||||
PanelManager(QObject* parent);
|
||||
|
||||
void DeleteAllPanels();
|
||||
|
||||
/**
|
||||
* @brief Return the currently focused widget, or nullptr if nothing is focused
|
||||
*/
|
||||
|
||||
@@ -49,13 +49,16 @@ bool RenderInstance::Start()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create context object
|
||||
ctx_ = new QOpenGLContext();
|
||||
|
||||
// If we're sharing resources, set this up now
|
||||
if (share_ctx_ != nullptr) {
|
||||
ctx_.setShareContext(share_ctx_);
|
||||
ctx_->setShareContext(share_ctx_);
|
||||
}
|
||||
|
||||
// Create OpenGL context (automatically destroys any existing if there is one)
|
||||
if (!ctx_.create()) {
|
||||
if (!ctx_->create()) {
|
||||
qWarning() << tr("Failed to create OpenGL context in thread %1").arg(reinterpret_cast<quintptr>(this));
|
||||
return false;
|
||||
}
|
||||
@@ -64,16 +67,16 @@ bool RenderInstance::Start()
|
||||
surface_.create();
|
||||
|
||||
// Make context current on that surface
|
||||
if (!ctx_.makeCurrent(&surface_)) {
|
||||
if (!ctx_->makeCurrent(&surface_)) {
|
||||
qWarning() << tr("Failed to makeCurrent() on offscreen surface in thread %1").arg(reinterpret_cast<quintptr>(this));
|
||||
surface_.destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer_.Create(&ctx_);
|
||||
buffer_.Create(ctx_);
|
||||
|
||||
// Set viewport to the compositing dimensions
|
||||
ctx_.functions()->glViewport(0, 0, width_, height_);
|
||||
ctx_->functions()->glViewport(0, 0, width_, height_);
|
||||
|
||||
// Set up default pipeline
|
||||
default_pipeline_ = olive::ShaderGenerator::DefaultPipeline();
|
||||
@@ -83,14 +86,18 @@ bool RenderInstance::Start()
|
||||
|
||||
void RenderInstance::Stop()
|
||||
{
|
||||
if (IsStarted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Destroy pipeline
|
||||
default_pipeline_ = nullptr;
|
||||
|
||||
// Destroy buffer
|
||||
buffer_.Destroy();
|
||||
|
||||
// Release OpenGL context
|
||||
ctx_.doneCurrent();
|
||||
// Destroy context
|
||||
delete ctx_;
|
||||
|
||||
// Destroy offscreen surface
|
||||
surface_.destroy();
|
||||
@@ -108,7 +115,7 @@ RenderFramebuffer *RenderInstance::buffer()
|
||||
|
||||
QOpenGLContext *RenderInstance::context()
|
||||
{
|
||||
return &ctx_;
|
||||
return ctx_;
|
||||
}
|
||||
|
||||
const int &RenderInstance::width() const
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
ShaderPtr default_pipeline() const;
|
||||
|
||||
private:
|
||||
QOpenGLContext ctx_;
|
||||
QOpenGLContext* ctx_;
|
||||
|
||||
QOpenGLContext* share_ctx_;
|
||||
|
||||
|
||||
@@ -32,13 +32,25 @@ NodeView::NodeView(QWidget *parent) :
|
||||
connect(&scene_, SIGNAL(selectionChanged()), this, SLOT(SceneSelectionChangedSlot()));
|
||||
}
|
||||
|
||||
NodeView::~NodeView()
|
||||
{
|
||||
// Unset the current graph
|
||||
SetGraph(nullptr);
|
||||
}
|
||||
|
||||
void NodeView::SetGraph(NodeGraph *graph)
|
||||
{
|
||||
if (graph_ == graph) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (graph_ != nullptr) {
|
||||
disconnect(graph_, SIGNAL(NodeAdded(Node*)), this, SLOT(AddNode(Node*)));
|
||||
disconnect(graph_, SIGNAL(NodeRemoved(Node*)), this, SLOT(RemoveNode(Node*)));
|
||||
disconnect(graph_, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(AddEdge(NodeEdgePtr)));
|
||||
disconnect(graph_, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(RemoveEdge(NodeEdgePtr)));
|
||||
|
||||
graph_->Release();
|
||||
}
|
||||
|
||||
// Clear the scene of all UI objects
|
||||
|
||||
@@ -39,6 +39,8 @@ class NodeView : public QGraphicsView
|
||||
public:
|
||||
NodeView(QWidget* parent);
|
||||
|
||||
virtual ~NodeView() override;
|
||||
|
||||
/**
|
||||
* @brief Sets the graph to view
|
||||
*/
|
||||
|
||||
@@ -79,3 +79,20 @@ void olive::MainWindow::ProjectOpen(Project* p)
|
||||
|
||||
connect(node_panel, SIGNAL(SelectionChanged(QList<Node*>)), param_panel, SLOT(SetNodes(QList<Node*>)));
|
||||
}
|
||||
|
||||
// FIXME: Test code
|
||||
#include <QDir>
|
||||
#include "common/filefunctions.h"
|
||||
// End test code
|
||||
|
||||
void olive::MainWindow::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
olive::panel_focus_manager->DeleteAllPanels();
|
||||
|
||||
// FIXME: Test code - We have no cache management and the cache is very much testing only, so we delete it on close
|
||||
// as to not clog up HDD space
|
||||
QDir(GetMediaCacheLocation()).removeRecursively();
|
||||
// End test code
|
||||
|
||||
QMainWindow::closeEvent(e);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ public:
|
||||
public slots:
|
||||
void ProjectOpen(Project *p);
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent* e) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user