fixed various caching issues
This commit is contained in:
@@ -27,6 +27,7 @@ Block::Block() :
|
||||
{
|
||||
previous_input_ = new NodeInput("prev_block");
|
||||
previous_input_->add_data_input(NodeParam::kBlock);
|
||||
previous_input_->set_dependent(false);
|
||||
AddParameter(previous_input_);
|
||||
|
||||
block_output_ = new NodeOutput("block_out");
|
||||
@@ -63,8 +64,12 @@ const rational& Block::length()
|
||||
|
||||
void Block::set_length(const rational &length)
|
||||
{
|
||||
Lock();
|
||||
|
||||
length_ = length;
|
||||
|
||||
Unlock();
|
||||
|
||||
RefreshFollowing();
|
||||
}
|
||||
|
||||
@@ -181,16 +186,6 @@ void Block::set_media_in(const rational &media_in)
|
||||
}
|
||||
}
|
||||
|
||||
QList<NodeDependency> Block::RunDependencies(NodeOutput* param, const rational &time)
|
||||
{
|
||||
// Base Blocks have no direct dependencies
|
||||
|
||||
Q_UNUSED(param)
|
||||
Q_UNUSED(time)
|
||||
|
||||
return QList<NodeDependency>();
|
||||
}
|
||||
|
||||
rational Block::SequenceToMediaTime(const rational &sequence_time)
|
||||
{
|
||||
// These constants are not considered "values" per se, so we don't modify them
|
||||
|
||||
@@ -67,11 +67,6 @@ public:
|
||||
const rational& media_in();
|
||||
void set_media_in(const rational& media_in);
|
||||
|
||||
/**
|
||||
* @brief Override removes previous input as that is not a direct dependency
|
||||
*/
|
||||
virtual QList<NodeDependency> RunDependencies(NodeOutput* output, const rational &time) override;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Refreshes internal cache of in/out points up to date
|
||||
|
||||
+33
-5
@@ -20,11 +20,13 @@
|
||||
|
||||
#include "input.h"
|
||||
|
||||
#include "node.h"
|
||||
#include "output.h"
|
||||
|
||||
NodeInput::NodeInput(const QString& id) :
|
||||
NodeParam(id),
|
||||
keyframing_(false)
|
||||
keyframing_(false),
|
||||
dependent_(true)
|
||||
{
|
||||
// Have at least one keyframe/value active at any time
|
||||
keyframes_.append(NodeKeyframe());
|
||||
@@ -74,8 +76,6 @@ QVariant NodeInput::get_value(const rational& time)
|
||||
{
|
||||
QVariant v;
|
||||
|
||||
lock_.lock();
|
||||
|
||||
if (time_ != time) {
|
||||
// Retrieve the value
|
||||
if (!edges_.isEmpty()) {
|
||||
@@ -92,13 +92,15 @@ QVariant NodeInput::get_value(const rational& time)
|
||||
|
||||
v = value_;
|
||||
|
||||
lock_.unlock();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void NodeInput::set_value(const QVariant &value)
|
||||
{
|
||||
bool lock_mutex = (parent() != nullptr);
|
||||
|
||||
if (lock_mutex) parent()->Lock();
|
||||
|
||||
if (keyframing()) {
|
||||
// FIXME: Keyframing code using time()
|
||||
} else {
|
||||
@@ -107,6 +109,8 @@ void NodeInput::set_value(const QVariant &value)
|
||||
|
||||
emit ValueChanged(RATIONAL_MIN, RATIONAL_MAX);
|
||||
}
|
||||
|
||||
if (lock_mutex) parent()->Unlock();
|
||||
}
|
||||
|
||||
bool NodeInput::keyframing()
|
||||
@@ -119,7 +123,31 @@ void NodeInput::set_keyframing(bool k)
|
||||
keyframing_ = k;
|
||||
}
|
||||
|
||||
bool NodeInput::dependent()
|
||||
{
|
||||
return dependent_;
|
||||
}
|
||||
|
||||
void NodeInput::set_dependent(bool d)
|
||||
{
|
||||
dependent_ = d;
|
||||
}
|
||||
|
||||
const QList<NodeParam::DataType> &NodeInput::inputs()
|
||||
{
|
||||
return inputs_;
|
||||
}
|
||||
|
||||
void NodeInput::CopyValues(NodeInput *source, NodeInput *dest)
|
||||
{
|
||||
// Copy values
|
||||
dest->keyframes_ = source->keyframes_;
|
||||
|
||||
// Copy keyframing state
|
||||
dest->set_keyframing(source->keyframing());
|
||||
|
||||
// Copy connections
|
||||
if (source->get_connected_output() != nullptr) {
|
||||
ConnectEdge(source->get_connected_output(), dest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,11 +103,28 @@ public:
|
||||
*/
|
||||
void set_keyframing(bool k);
|
||||
|
||||
/**
|
||||
* @brief Return whether the Node is dependent on this input or not
|
||||
*
|
||||
* \see set_dependent()
|
||||
*/
|
||||
bool dependent();
|
||||
|
||||
/**
|
||||
* @brief Set whether the Node is dependent on this input
|
||||
*/
|
||||
void set_dependent(bool d);
|
||||
|
||||
/**
|
||||
* @brief A list of input data types accepted by this parameter
|
||||
*/
|
||||
const QList<DataType>& inputs();
|
||||
|
||||
/**
|
||||
* @brief Copy all values including keyframe information and connections from another NodeInput
|
||||
*/
|
||||
static void CopyValues(NodeInput* source, NodeInput* dest);
|
||||
|
||||
signals:
|
||||
void ValueChanged(const rational& start, const rational& end);
|
||||
|
||||
@@ -132,6 +149,11 @@ private:
|
||||
*/
|
||||
bool keyframing_;
|
||||
|
||||
/**
|
||||
* @brief Internal dependent setting
|
||||
*/
|
||||
bool dependent_;
|
||||
|
||||
};
|
||||
|
||||
#endif // NODEINPUT_H
|
||||
|
||||
@@ -103,7 +103,6 @@ void MediaInput::Hash(QCryptographicHash *hash, NodeOutput *from, const rational
|
||||
|
||||
// Use frame value from Decoder
|
||||
if (from == texture_output_ && SetupDecoder()) {
|
||||
qDebug() << "[MediaInput] Hashing pts" << decoder_->GetTimestampFromTime(time);
|
||||
hash->addData(QString::number(decoder_->GetTimestampFromTime(time)).toUtf8());
|
||||
// FIXME: Add OCIO data
|
||||
// FIXME: Add alpha association value
|
||||
|
||||
+46
-13
@@ -98,6 +98,36 @@ void Node::InvalidateCache(const rational &start_range, const rational &end_rang
|
||||
}
|
||||
}
|
||||
|
||||
void Node::Lock()
|
||||
{
|
||||
lock_.lock();
|
||||
}
|
||||
|
||||
void Node::Unlock()
|
||||
{
|
||||
lock_.unlock();
|
||||
}
|
||||
|
||||
void Node::CopyInputs(Node *source, Node *destination)
|
||||
{
|
||||
Q_ASSERT(source->id() == destination->id());
|
||||
|
||||
QList<NodeParam*> src_param = source->parameters();
|
||||
QList<NodeParam*> dst_param = destination->parameters();
|
||||
|
||||
for (int i=0;i<src_param.size();i++) {
|
||||
if (src_param.at(i)->type() == NodeParam::kInput) {
|
||||
NodeInput* src = static_cast<NodeInput*>(src_param.at(i));
|
||||
|
||||
if (src->dependent()) {
|
||||
NodeInput* dst = static_cast<NodeInput*>(dst_param.at(i));
|
||||
|
||||
NodeInput::CopyValues(src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Node::IgnoreCacheInvalidationFrom(NodeInput *input)
|
||||
{
|
||||
ignore_invalid_cache_inputs_.append(input);
|
||||
@@ -131,13 +161,7 @@ NodeOutput *Node::LastProcessedOutput()
|
||||
|
||||
QVariant Node::Run(NodeOutput* output, const rational& time)
|
||||
{
|
||||
lock_.lock();
|
||||
|
||||
QVariant v = Value(output, time);
|
||||
|
||||
lock_.unlock();
|
||||
|
||||
return v;
|
||||
return Value(output, time);
|
||||
}
|
||||
|
||||
NodeParam *Node::ParamAt(int index)
|
||||
@@ -178,7 +202,9 @@ void GetDependenciesInternal(Node* n, QList<Node*>& list, bool traverse) {
|
||||
foreach (NodeEdgePtr edge, param_edges) {
|
||||
Node* connected_node = edge->output()->parent();
|
||||
|
||||
list.append(connected_node);
|
||||
if (!list.contains(connected_node)) {
|
||||
list.append(connected_node);
|
||||
}
|
||||
|
||||
if (traverse) {
|
||||
GetDependenciesInternal(connected_node, list, traverse);
|
||||
@@ -250,13 +276,17 @@ QList<NodeDependency> Node::RunDependencies(NodeOutput *output, const rational &
|
||||
|
||||
foreach (NodeParam* p, params) {
|
||||
if (p->type() == NodeParam::kInput) {
|
||||
NodeOutput* potential_dep = static_cast<NodeInput*>(p)->get_connected_output();
|
||||
NodeInput* input = static_cast<NodeInput*>(p);
|
||||
|
||||
if (potential_dep != nullptr) {
|
||||
run_deps.append(NodeDependency(potential_dep, time));
|
||||
// Check if Node is dependent on this input or not
|
||||
if (input->dependent()) {
|
||||
NodeOutput* potential_dep = input->get_connected_output();
|
||||
|
||||
if (potential_dep != nullptr) {
|
||||
run_deps.append(NodeDependency(potential_dep, time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return run_deps;
|
||||
@@ -285,11 +315,14 @@ 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();
|
||||
foreach (NodeParam* param, params) {
|
||||
if (param->type() == NodeParam::kInput && !param->IsConnected()) {
|
||||
if (param->type() == NodeParam::kInput
|
||||
&& !param->IsConnected()
|
||||
&& static_cast<NodeInput*>(param)->dependent()) {
|
||||
// Get the value at this time
|
||||
QVariant v = static_cast<NodeInput*>(param)->get_value(time);
|
||||
hash->addData(v.toByteArray()); // FIXME: Does this work on all value types?
|
||||
|
||||
+20
-3
@@ -130,9 +130,9 @@ public:
|
||||
QList<Node*> GetImmediateDependencies();
|
||||
|
||||
/**
|
||||
* @brief Thread-safe wrapper for Process()
|
||||
* @brief Wrapper for Process()
|
||||
*
|
||||
* It's recommended to call this directly over Process(), yet in derivatives of Node, override Process().
|
||||
* It's recommended to call this directly over Value(), yet in derivatives of Node, override Value().
|
||||
*/
|
||||
QVariant Run(NodeOutput* output, const rational& time);
|
||||
|
||||
@@ -175,6 +175,23 @@ public:
|
||||
*/
|
||||
virtual void InvalidateCache(const rational& start_range, const rational& end_range, NodeInput* from = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Lock mutex (for thread safety)
|
||||
*/
|
||||
void Lock();
|
||||
|
||||
/**
|
||||
* @brief Unock mutex (for thread safety)
|
||||
*/
|
||||
void Unlock();
|
||||
|
||||
/**
|
||||
* @brief Copies inputs from from Node to another including connections
|
||||
*
|
||||
* Nodes must be of the same types (i.e. have the same ID)
|
||||
*/
|
||||
static void CopyInputs(Node* source, Node* destination);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Add a parameter to this node
|
||||
@@ -265,7 +282,7 @@ private:
|
||||
NodeOutput* last_processed_parameter_;
|
||||
|
||||
/**
|
||||
* @brief Used for thread safety in Run()
|
||||
* @brief Used for thread safety
|
||||
*/
|
||||
QMutex lock_;
|
||||
|
||||
|
||||
@@ -51,8 +51,6 @@ QVariant NodeOutput::get_value(const rational& time)
|
||||
{
|
||||
QVariant v;
|
||||
|
||||
lock_.lock();
|
||||
|
||||
if (time_ != time) {
|
||||
// Update the value
|
||||
value_ = parent()->Run(this, time);
|
||||
@@ -62,8 +60,6 @@ QVariant NodeOutput::get_value(const rational& time)
|
||||
|
||||
v = value_;
|
||||
|
||||
lock_.unlock();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ TrackOutput::TrackOutput() :
|
||||
{
|
||||
track_input_ = new NodeInput("track_in");
|
||||
track_input_->add_data_input(NodeParam::kTrack);
|
||||
track_input_->set_dependent(false);
|
||||
AddParameter(track_input_);
|
||||
|
||||
track_output_ = new NodeOutput("track_out");
|
||||
@@ -359,6 +360,10 @@ void TrackOutput::RemoveBlock(Block *block)
|
||||
|
||||
void TrackOutput::RippleRemoveBlock(Block *block)
|
||||
{
|
||||
BlockInvalidateCache();
|
||||
|
||||
rational remove_in = block->in();
|
||||
|
||||
Block* previous = block->previous();
|
||||
Block* next = block->next();
|
||||
|
||||
@@ -374,6 +379,10 @@ void TrackOutput::RippleRemoveBlock(Block *block)
|
||||
Block::ConnectBlocks(previous, next);
|
||||
}
|
||||
|
||||
UnblockInvalidateCache();
|
||||
|
||||
InvalidateCache(remove_in, in());
|
||||
|
||||
// FIXME: Should there be removing the Blocks from the graph?
|
||||
}
|
||||
|
||||
@@ -391,8 +400,12 @@ Block* TrackOutput::SplitBlock(Block *block, rational time)
|
||||
|
||||
Block* copy = block->copy();
|
||||
copy->set_length(original_length - block->length());
|
||||
copy->set_media_in(block->media_in() + block->length());
|
||||
|
||||
InsertBlockAfter(copy, block);
|
||||
|
||||
Node::CopyInputs(block, copy);
|
||||
|
||||
UnblockInvalidateCache();
|
||||
|
||||
return copy;
|
||||
@@ -449,6 +462,8 @@ void TrackOutput::RippleRemoveArea(rational in, rational out, Block *insert)
|
||||
}
|
||||
}
|
||||
|
||||
BlockInvalidateCache();
|
||||
|
||||
// If we picked up a block to splice
|
||||
if (splice != nullptr) {
|
||||
|
||||
@@ -495,6 +510,10 @@ void TrackOutput::RippleRemoveArea(rational in, rational out, Block *insert)
|
||||
InsertBlockBetweenBlocks(insert, trim_out_to_in, trim_in_to_out);
|
||||
}
|
||||
}
|
||||
|
||||
UnblockInvalidateCache();
|
||||
|
||||
InvalidateCache(in, out);
|
||||
}
|
||||
|
||||
void TrackOutput::ReplaceBlock(Block *old, Block *replace)
|
||||
|
||||
@@ -149,11 +149,17 @@ NodeEdgePtr NodeParam::ConnectEdge(NodeOutput *output, NodeInput *input)
|
||||
|
||||
NodeEdgePtr edge = std::make_shared<NodeEdge>(output, input);
|
||||
|
||||
output->parent()->Lock();
|
||||
input->parent()->Lock();
|
||||
|
||||
output->edges_.append(edge);
|
||||
input->edges_.append(edge);
|
||||
|
||||
input->ClearCachedValue();
|
||||
|
||||
output->parent()->Unlock();
|
||||
input->parent()->Unlock();
|
||||
|
||||
// Emit a signal than an edge was added (only one signal needs emitting)
|
||||
emit input->EdgeAdded(edge);
|
||||
|
||||
@@ -165,11 +171,17 @@ void NodeParam::DisconnectEdge(NodeEdgePtr edge)
|
||||
NodeOutput* output = edge->output();
|
||||
NodeInput* input = edge->input();
|
||||
|
||||
output->parent()->Lock();
|
||||
input->parent()->Lock();
|
||||
|
||||
output->edges_.removeAll(edge);
|
||||
input->edges_.removeAll(edge);
|
||||
|
||||
input->ClearCachedValue();
|
||||
|
||||
output->parent()->Unlock();
|
||||
input->parent()->Unlock();
|
||||
|
||||
emit input->EdgeRemoved(edge);
|
||||
}
|
||||
|
||||
|
||||
@@ -231,11 +231,6 @@ protected:
|
||||
*/
|
||||
QVector<NodeEdgePtr> edges_;
|
||||
|
||||
/**
|
||||
* @brief Used for thread safety
|
||||
*/
|
||||
QMutex lock_;
|
||||
|
||||
/**
|
||||
* @brief Currently cached value
|
||||
*/
|
||||
|
||||
@@ -98,6 +98,8 @@ 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]);
|
||||
|
||||
if (QFileInfo::exists(fn)) {
|
||||
@@ -362,6 +364,8 @@ void RendererProcessor::DownloadThreadFinished(const rational& time)
|
||||
texture_output_->ClearCachedValue();
|
||||
|
||||
foreach (NodeEdgePtr edge, edges) {
|
||||
edge->input()->ClearCachedValue();
|
||||
|
||||
edge->input()->parent()->InvalidateCache(time,
|
||||
time,
|
||||
edge->input());
|
||||
|
||||
@@ -85,11 +85,20 @@ void RendererProcessThread::ProcessLoop()
|
||||
NodeOutput* output_to_process = path_.node();
|
||||
Node* node_to_process = output_to_process->parent();
|
||||
|
||||
node_to_process->Lock();
|
||||
|
||||
QList<Node*> all_deps = node_to_process->GetDependencies();
|
||||
foreach (Node* dep, all_deps) {
|
||||
dep->Lock();
|
||||
}
|
||||
|
||||
// Check hash
|
||||
QCryptographicHash hasher(QCryptographicHash::Sha1);
|
||||
node_to_process->Hash(&hasher, output_to_process, path_.time());
|
||||
hash_ = hasher.result();
|
||||
|
||||
texture_ = nullptr;
|
||||
|
||||
if (!parent_->HasHash(hash_)) {
|
||||
QList<NodeDependency> deps = node_to_process->RunDependencies(output_to_process, path_.time());
|
||||
|
||||
@@ -106,6 +115,12 @@ void RendererProcessThread::ProcessLoop()
|
||||
render_instance()->context()->functions()->glFinish();
|
||||
}
|
||||
|
||||
foreach (Node* dep, all_deps) {
|
||||
dep->Unlock();
|
||||
}
|
||||
|
||||
node_to_process->Unlock();
|
||||
|
||||
emit FinishedPath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ RendererThreadBase::RendererThreadBase(QOpenGLContext *share_ctx, const int &wid
|
||||
mode_(mode),
|
||||
render_instance_(nullptr)
|
||||
{
|
||||
connect(share_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Cancel()));
|
||||
}
|
||||
|
||||
void RendererThreadBase::Cancel()
|
||||
|
||||
@@ -39,14 +39,15 @@ public:
|
||||
const olive::PixelFormat& format,
|
||||
const olive::RenderMode& mode);
|
||||
|
||||
void Cancel();
|
||||
|
||||
RenderInstance* render_instance();
|
||||
|
||||
void StartThread(Priority priority = InheritPriority);
|
||||
|
||||
virtual void run() override;
|
||||
|
||||
public slots:
|
||||
void Cancel();
|
||||
|
||||
protected:
|
||||
virtual void ProcessLoop() = 0;
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ void RenderFramebuffer::Create(QOpenGLContext *ctx)
|
||||
|
||||
context_ = ctx;
|
||||
|
||||
connect(context_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()));
|
||||
|
||||
// Create framebuffer object
|
||||
context_->functions()->glGenFramebuffers(1, &buffer_);
|
||||
}
|
||||
@@ -55,6 +57,8 @@ void RenderFramebuffer::Create(QOpenGLContext *ctx)
|
||||
void RenderFramebuffer::Destroy()
|
||||
{
|
||||
if (context_ != nullptr) {
|
||||
disconnect(context_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()));
|
||||
|
||||
context_->functions()->glDeleteFramebuffers(1, &buffer_);
|
||||
|
||||
buffer_ = 0;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
class RenderFramebuffer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RenderFramebuffer();
|
||||
~RenderFramebuffer();
|
||||
@@ -37,8 +38,6 @@ public:
|
||||
|
||||
void Create(QOpenGLContext *ctx);
|
||||
|
||||
void Destroy();
|
||||
|
||||
bool IsCreated() const;
|
||||
|
||||
void Bind();
|
||||
@@ -53,6 +52,9 @@ public:
|
||||
|
||||
const GLuint& buffer() const;
|
||||
|
||||
public slots:
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
void AttachInternal(GLuint tex);
|
||||
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
|
||||
#include "render/pixelservice.h"
|
||||
|
||||
// FIXME: Test code
|
||||
QMutex m;
|
||||
// End test code
|
||||
|
||||
RenderTexture::RenderTexture() :
|
||||
context_(nullptr),
|
||||
texture_(0)
|
||||
@@ -64,6 +60,8 @@ void RenderTexture::Create(QOpenGLContext *ctx, int width, int height, const oli
|
||||
height_ = height;
|
||||
format_ = format;
|
||||
|
||||
connect(context_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()));
|
||||
|
||||
// Create main texture
|
||||
CreateInternal(&texture_, data);
|
||||
|
||||
@@ -76,6 +74,8 @@ void RenderTexture::Create(QOpenGLContext *ctx, int width, int height, const oli
|
||||
void RenderTexture::Destroy()
|
||||
{
|
||||
if (context_ != nullptr) {
|
||||
disconnect(context_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()));
|
||||
|
||||
context_->functions()->glDeleteTextures(1, &texture_);
|
||||
texture_ = 0;
|
||||
|
||||
|
||||
@@ -26,13 +26,9 @@
|
||||
|
||||
#include "pixelformat.h"
|
||||
|
||||
// FIXME: Test code
|
||||
#include <QMutex>
|
||||
extern QMutex m;
|
||||
// End test code
|
||||
|
||||
class RenderTexture : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Type {
|
||||
kSingleBuffer,
|
||||
@@ -51,8 +47,6 @@ public:
|
||||
|
||||
bool IsCreated() const;
|
||||
|
||||
void Destroy();
|
||||
|
||||
void Bind();
|
||||
|
||||
void Release();
|
||||
@@ -73,6 +67,9 @@ public:
|
||||
|
||||
uchar *Download() const;
|
||||
|
||||
public slots:
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
void CreateInternal(GLuint *tex, void *data = nullptr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user