nodes: improved changed signal processing

Improves stability and cache reliability.

Earlier iterations were prone to skipping necessary signals (usually
leading to some sort of assert fail), particularly when track
optimizations were used. Those optimizations have been moved to the
viewer node so there's a higher degree of control over which signals
get optimized and in which ways.
This commit is contained in:
itsmattkc
2020-07-16 00:32:00 +10:00
parent e67b801a50
commit de74adeb5e
9 changed files with 128 additions and 118 deletions
-10
View File
@@ -355,16 +355,6 @@ NodeInput *Block::speed_input() const
return speed_input_;
}
void Block::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
{
if (range.out() <= in() || range.in() >= out()) {
// Ignore this range
return;
}
Node::InvalidateCache(TimeRange(qMax(range.in(), in()), qMin(range.out(), out())), from, source);
}
void Block::Hash(QCryptographicHash &, const rational &) const
{
// A block does nothing by default, so we hash nothing
-2
View File
@@ -88,8 +88,6 @@ public:
NodeInput* media_in_input() const;
NodeInput* speed_input() const;
virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput* source) override;
virtual void Hash(QCryptographicHash &hash, const rational &time) const override;
public slots:
+23 -4
View File
@@ -177,6 +177,28 @@ void Node::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *s
SendInvalidateCache(range, source);
}
void Node::BeginOperation()
{
foreach (NodeParam* param, params_) {
if (param->type() == NodeParam::kOutput) {
foreach (NodeEdgePtr edge, param->edges()) {
edge->input()->parentNode()->BeginOperation();
}
}
}
}
void Node::EndOperation()
{
foreach (NodeParam* param, params_) {
if (param->type() == NodeParam::kOutput) {
foreach (NodeEdgePtr edge, param->edges()) {
edge->input()->parentNode()->EndOperation();
}
}
}
}
TimeRange Node::InputTimeAdjustment(NodeInput *, const TimeRange &input_time) const
{
// Default behavior is no time adjustment at all
@@ -195,10 +217,7 @@ void Node::SendInvalidateCache(const TimeRange &range, NodeInput *source)
foreach (NodeParam* param, params_) {
// If the Node is an output, relay the signal to any Nodes that are connected to it
if (param->type() == NodeParam::kOutput) {
QVector<NodeEdgePtr> edges = param->edges();
foreach (NodeEdgePtr edge, edges) {
foreach (NodeEdgePtr edge, param->edges()) {
NodeInput* connected_input = edge->input();
Node* connected_node = connected_input->parentNode();
+13
View File
@@ -304,6 +304,19 @@ public:
*/
virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput* source);
/**
* @brief Limits cache invalidation temporarily
*
* If you intend to do a number of operations in quick succession, you can optimize it by running
* this function with EndOperation().
*/
virtual void BeginOperation();
/**
* @brief Stops limiting cache invalidation and flushes changes
*/
virtual void EndOperation();
/**
* @brief Adjusts time that should be sent to nodes connected to certain inputs.
*
+27 -43
View File
@@ -31,10 +31,8 @@ OLIVE_NAMESPACE_ENTER
TrackOutput::TrackOutput() :
track_type_(Timeline::kTrackTypeNone),
block_invalidate_cache_stack_(0),
index_(-1),
locked_(false),
queued_length_change_(false)
locked_(false)
{
block_input_ = new NodeInputArray("block_in", NodeParam::kAny);
block_input_->set_is_keyframable(false);
@@ -252,11 +250,24 @@ const QList<Block *> &TrackOutput::Blocks() const
void TrackOutput::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
{
if (block_invalidate_cache_stack_ == 0) {
PushLengthChangeSignal(true);
TimeRange limited;
Node::InvalidateCache(TimeRange(qMax(range.in(), rational(0)), qMin(range.out(), track_length())), from, source);
if (block_input_->sub_params().contains(from)
&& from->get_connected_node()
&& from->get_connected_node()->IsBlock()) {
// Limit the range signal to the corresponding block
Block* b = static_cast<Block*>(from->get_connected_node());
if (range.out() <= b->in() || range.in() >= b->out()) {
return;
}
limited = TimeRange(qMax(range.in(), b->in()), qMin(range.out(), b->out()));
} else {
limited = TimeRange(qMax(range.in(), rational(0)), qMin(range.out(), track_length()));
}
Node::InvalidateCache(limited, from, source);
}
void TrackOutput::InsertBlockBefore(Block* block, Block* after)
@@ -279,12 +290,12 @@ void TrackOutput::InsertBlockAfter(Block *block, Block *before)
void TrackOutput::PrependBlock(Block *block)
{
BlockInvalidateCache();
BeginOperation();
block_input_->Prepend();
NodeParam::ConnectEdge(block->output(), block_input_->First());
UnblockInvalidateCache();
EndOperation();
// Everything has shifted at this point
InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_);
@@ -292,57 +303,47 @@ void TrackOutput::PrependBlock(Block *block)
void TrackOutput::InsertBlockAtIndex(Block *block, int index)
{
BlockInvalidateCache();
BeginOperation();
int insert_index = GetInputIndexFromCacheIndex(index);
block_input_->InsertAt(insert_index);
NodeParam::ConnectEdge(block->output(),
block_input_->At(insert_index));
UnblockInvalidateCache();
EndOperation();
InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_);
}
void TrackOutput::AppendBlock(Block *block)
{
BlockInvalidateCache();
BeginOperation();
block_input_->Append();
NodeParam::ConnectEdge(block->output(), block_input_->Last());
UnblockInvalidateCache();
EndOperation();
// Invalidate area that block was added to
InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_);
}
void TrackOutput::BlockInvalidateCache()
{
block_invalidate_cache_stack_++;
}
void TrackOutput::UnblockInvalidateCache()
{
block_invalidate_cache_stack_--;
}
void TrackOutput::RippleRemoveBlock(Block *block)
{
BlockInvalidateCache();
BeginOperation();
rational remove_in = block->in();
block_input_->RemoveAt(GetInputIndexFromCacheIndex(block));
UnblockInvalidateCache();
EndOperation();
InvalidateCache(TimeRange(remove_in, track_length()), block_input_, block_input_);
}
void TrackOutput::ReplaceBlock(Block *old, Block *replace)
{
BlockInvalidateCache();
BeginOperation();
int index_of_old_block = GetInputIndexFromCacheIndex(old);
@@ -352,7 +353,7 @@ void TrackOutput::ReplaceBlock(Block *old, Block *replace)
NodeParam::ConnectEdge(replace->output(),
block_input_->At(index_of_old_block));
UnblockInvalidateCache();
EndOperation();
if (old->length() == replace->length()) {
InvalidateCache(TimeRange(replace->in(), replace->out()), block_input_, block_input_);
@@ -443,14 +444,6 @@ void TrackOutput::Hash(QCryptographicHash &hash, const rational &time) const
}
}
void TrackOutput::PushLengthChangeSignal(bool invalidate)
{
if (queued_length_change_) {
queued_length_change_ = false;
SetLengthInternal(queued_length_, invalidate);
}
}
void TrackOutput::SetTrackName(const QString &name)
{
track_name_ = name;
@@ -507,15 +500,6 @@ int TrackOutput::GetInputIndexFromCacheIndex(Block *block)
void TrackOutput::SetLengthInternal(const rational &r, bool invalidate)
{
if (block_invalidate_cache_stack_ > 0) {
queued_length_change_ = true;
}
if (queued_length_change_) {
queued_length_ = r;
return;
}
if (r != track_length_) {
TimeRange invalidate_range(track_length_, r);
-11
View File
@@ -166,10 +166,6 @@ public:
*/
void ReplaceBlock(Block* old, Block* replace);
void BlockInvalidateCache();
void UnblockInvalidateCache();
static TrackOutput* TrackFromBlock(const Block *block);
const rational& track_length() const;
@@ -192,8 +188,6 @@ public:
virtual void Hash(QCryptographicHash& hash, const rational &time) const override;
void PushLengthChangeSignal(bool invalidate = false);
AudioVisualWaveform& waveform()
{
return waveform_;
@@ -274,15 +268,10 @@ private:
QString track_name_;
int block_invalidate_cache_stack_;
int index_;
bool locked_;
bool queued_length_change_;
rational queued_length_;
AudioVisualWaveform waveform_;
QMutex waveform_lock_;
+29 -12
View File
@@ -26,7 +26,8 @@ OLIVE_NAMESPACE_ENTER
ViewerOutput::ViewerOutput() :
video_frame_cache_(this),
audio_playback_cache_(this)
audio_playback_cache_(this),
operation_stack_(0)
{
texture_input_ = new NodeInput("tex_in", NodeInput::kTexture);
AddInput(texture_input_);
@@ -49,7 +50,7 @@ ViewerOutput::ViewerOutput() :
TrackList* list = new TrackList(this, static_cast<Timeline::TrackType>(i), track_input);
track_lists_.replace(i, list);
connect(list, &TrackList::TrackListChanged, this, &ViewerOutput::UpdateTrackCache);
connect(list, &TrackList::LengthChanged, this, &ViewerOutput::VerifyLength);
//connect(list, &TrackList::LengthChanged, this, &ViewerOutput::VerifyLength);
connect(list, &TrackList::BlockAdded, this, &ViewerOutput::TrackListAddedBlock);
connect(list, &TrackList::BlockRemoved, this, &ViewerOutput::BlockRemoved);
connect(list, &TrackList::TrackAdded, this, &ViewerOutput::TrackListAddedTrack);
@@ -111,20 +112,22 @@ void ViewerOutput::InvalidateCache(const TimeRange &range, NodeInput *from, Node
{
emit GraphChangedFrom(source);
if (from == texture_input_ || from == samples_input_) {
TimeRange invalidated_range(qMax(rational(), range.in()),
qMin(GetLength(), range.out()));
if (operation_stack_ == 0) {
if (from == texture_input_ || from == samples_input_) {
TimeRange invalidated_range(qMax(rational(), range.in()),
qMin(GetLength(), range.out()));
if (invalidated_range.in() != invalidated_range.out()) {
if (from == texture_input_) {
video_frame_cache_.Invalidate(invalidated_range);
} else {
audio_playback_cache_.Invalidate(invalidated_range);
if (invalidated_range.in() != invalidated_range.out()) {
if (from == texture_input_) {
video_frame_cache_.Invalidate(invalidated_range);
} else {
audio_playback_cache_.Invalidate(invalidated_range);
}
}
}
}
VerifyLength();
VerifyLength();
}
Node::InvalidateCache(range, from, source);
}
@@ -257,6 +260,20 @@ void ViewerOutput::set_media_name(const QString &name)
emit MediaNameChanged(media_name_);
}
void ViewerOutput::BeginOperation()
{
operation_stack_++;
Node::BeginOperation();
}
void ViewerOutput::EndOperation()
{
operation_stack_--;
Node::EndOperation();
}
void ViewerOutput::TrackListAddedBlock(Block *block, int index)
{
Timeline::TrackType type = static_cast<TrackList*>(sender())->type();
+6
View File
@@ -118,6 +118,10 @@ public:
return &audio_playback_cache_;
}
virtual void BeginOperation() override;
virtual void EndOperation() override;
signals:
void TimebaseChanged(const rational&);
@@ -164,6 +168,8 @@ private:
AudioPlaybackCache audio_playback_cache_;
int operation_stack_;
private slots:
void UpdateTrackCache();