rewrote renderers where necessary for new node structure
Largely conforming renderers to new NodeValue system. Code seems a lot cleaner this way which is a nice advantage. Likely non-functional as this won't compile just yet and still needs probably another day or two of testing to get it back to where it was before.
This commit is contained in:
+30
-25
@@ -27,31 +27,7 @@ void NodeValueDatabase::Insert(const NodeInput *key, const NodeValueTable &value
|
||||
|
||||
NodeValueTable NodeValueDatabase::Merge() const
|
||||
{
|
||||
if (tables_.size() == 1) {
|
||||
return tables_.begin().value();
|
||||
}
|
||||
|
||||
int row = 0;
|
||||
|
||||
NodeValueTable merged_table;
|
||||
|
||||
QHash<QString, NodeValueTable>::const_iterator iterator;
|
||||
|
||||
// Slipstreams all tables together
|
||||
// FIXME: I don't actually know if this is the right approach...
|
||||
for (iterator = tables_.begin();iterator != tables_.end();iterator++) {
|
||||
const NodeValueTable& table = iterator.value();
|
||||
|
||||
if (row >= table.Count()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int row_index = table.Count() - 1 - row;
|
||||
|
||||
merged_table.Prepend(table.At(row_index));
|
||||
}
|
||||
|
||||
return merged_table;
|
||||
return NodeValueTable::Merge(tables_.values());
|
||||
}
|
||||
|
||||
NodeValue::NodeValue(const NodeParam::DataType &type, const QVariant &data, const QString &tag) :
|
||||
@@ -125,6 +101,35 @@ bool NodeValueTable::isEmpty() const
|
||||
return values_.isEmpty();
|
||||
}
|
||||
|
||||
NodeValueTable NodeValueTable::Merge(QList<NodeValueTable> tables)
|
||||
{
|
||||
|
||||
|
||||
if (tables.size() == 1) {
|
||||
return tables.first();
|
||||
}
|
||||
|
||||
int row = 0;
|
||||
|
||||
NodeValueTable merged_table;
|
||||
|
||||
QHash<QString, NodeValueTable>::const_iterator iterator;
|
||||
|
||||
// Slipstreams all tables together
|
||||
// FIXME: I don't actually know if this is the right approach...
|
||||
foreach (const NodeValueTable& t, tables) {
|
||||
if (row >= t.Count()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int row_index = t.Count() - 1 - row;
|
||||
|
||||
merged_table.Prepend(t.At(row_index));
|
||||
}
|
||||
|
||||
return merged_table;
|
||||
}
|
||||
|
||||
QVariant NodeValueTable::GetInternal(const NodeParam::DataType &type, const QString &tag, bool remove)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
@@ -37,6 +37,8 @@ public:
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
static NodeValueTable Merge(QList<NodeValueTable> tables);
|
||||
|
||||
private:
|
||||
QVariant GetInternal(const NodeParam::DataType& type, const QString& tag, bool remove);
|
||||
|
||||
|
||||
@@ -62,14 +62,14 @@ void AudioBackend::DecompileInternal()
|
||||
|
||||
void AudioBackend::ConnectWorkerToThis(RenderWorker *worker)
|
||||
{
|
||||
connect(worker, SIGNAL(CompletedCache(NodeDependency)), this, SLOT(ThreadCompletedCache(NodeDependency)));
|
||||
connect(worker, SIGNAL(CompletedCache(NodeDependency, QVariant)), this, SLOT(ThreadCompletedCache(NodeDependency, QVariant)));
|
||||
}
|
||||
|
||||
void AudioBackend::ThreadCompletedCache(NodeDependency dep)
|
||||
void AudioBackend::ThreadCompletedCache(NodeDependency dep, QVariant data)
|
||||
{
|
||||
caching_ = false;
|
||||
|
||||
QByteArray cached_samples = dep.node()->get_cached_value(dep.range()).toByteArray();
|
||||
QByteArray cached_samples = data.toByteArray();
|
||||
|
||||
int offset = params().time_to_bytes(dep.in());
|
||||
int length = params().time_to_bytes(dep.range().length());
|
||||
|
||||
@@ -30,7 +30,7 @@ protected:
|
||||
virtual void ConnectWorkerToThis(RenderWorker* worker) override;
|
||||
|
||||
private slots:
|
||||
void ThreadCompletedCache(NodeDependency dep);
|
||||
void ThreadCompletedCache(NodeDependency dep, QVariant data);
|
||||
|
||||
private:
|
||||
QFile pull_device_;
|
||||
|
||||
@@ -16,8 +16,8 @@ bool AudioWorker::OutputIsAccelerated(NodeOutput *output)
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant AudioWorker::RunNodeAccelerated(NodeOutput *output)
|
||||
NodeValueTable AudioWorker::RunNodeAccelerated(NodeOutput *output)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
return QVariant();
|
||||
return NodeValueTable();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ protected:
|
||||
|
||||
virtual bool OutputIsAccelerated(NodeOutput *output) override;
|
||||
|
||||
virtual QVariant RunNodeAccelerated(NodeOutput *output) override;
|
||||
virtual NodeValueTable RunNodeAccelerated(NodeOutput *output) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -12,35 +12,6 @@ void AudioRenderWorker::SetParameters(const AudioRenderingParams &audio_params)
|
||||
audio_params_ = audio_params;
|
||||
}
|
||||
|
||||
QVariant AudioRenderWorker::RenderAsSibling(NodeDependency dep)
|
||||
{
|
||||
NodeOutput* output = dep.node();
|
||||
Node* node = output->parentNode();
|
||||
QList<NodeInput*> connected_inputs;
|
||||
QVariant value;
|
||||
|
||||
// Set working state
|
||||
working_++;
|
||||
|
||||
// Firstly we check if this node is a "Block", if it is that means it's part of a linked list of mutually exclusive
|
||||
// nodes based on time and we might need to locate which Block to attach to
|
||||
if (node->IsBlock()
|
||||
&& (dep.range().in() < static_cast<Block*>(node)->in()
|
||||
|| dep.range().out() > static_cast<Block*>(node)->out())) {
|
||||
// If the range is not wholly contained in this Block, we'll need to do some extra processing
|
||||
value = RenderBlock(output, dep.range());
|
||||
} else {
|
||||
value = ProcessNodeNormally(NodeDependency(output, dep.range()));
|
||||
}
|
||||
|
||||
// We're done!
|
||||
|
||||
// End this working state
|
||||
working_--;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool AudioRenderWorker::InitInternal()
|
||||
{
|
||||
// Nothing to init yet
|
||||
@@ -52,63 +23,51 @@ void AudioRenderWorker::CloseInternal()
|
||||
// Nothing to init yet
|
||||
}
|
||||
|
||||
QVariant AudioRenderWorker::RenderBlock(NodeOutput* output, const TimeRange &range)
|
||||
FramePtr AudioRenderWorker::RetrieveFromDecoder(DecoderPtr decoder, const TimeRange &range)
|
||||
{
|
||||
return decoder->RetrieveAudio(range.in(), range.out() - range.in(), audio_params_);
|
||||
}
|
||||
|
||||
NodeValueTable AudioRenderWorker::RenderBlock(NodeOutput* output, const TimeRange &range)
|
||||
{
|
||||
QList<Block*> active_blocks = ValidateBlockRange(static_cast<Block*>(output->parentNode()), range);
|
||||
|
||||
// All these blocks will need to output to a buffer so we create one here
|
||||
QByteArray block_range_buffer(audio_params_.time_to_bytes(range.length()), 0);
|
||||
|
||||
NodeValueTable merged_table;
|
||||
|
||||
// Loop through active blocks retrieving their audio
|
||||
while (!active_blocks.isEmpty()) {
|
||||
int block_for_this_thread = -1;
|
||||
foreach (Block* b, active_blocks) {
|
||||
TimeRange range_for_block(qMax(b->in(), range.in()),
|
||||
qMin(b->out(), range.out()));
|
||||
|
||||
for (int i=0;i<active_blocks.size();i++) {
|
||||
Block* b = active_blocks.at(i);
|
||||
NodeOutput* connected_output = static_cast<NodeOutput*>(b->GetParameterWithID(output->id()));
|
||||
NodeValueTable table = RenderAsSibling(NodeDependency(b->block_output(),
|
||||
range_for_block));
|
||||
|
||||
TimeRange range_for_block(qMax(b->in(), range.in()),
|
||||
qMin(b->out(), range.out()));
|
||||
QByteArray samples_from_this_block = table.Take(NodeParam::kSamples).toByteArray();
|
||||
int destination_offset = audio_params_.time_to_bytes(range_for_block.in() - range.in());
|
||||
int maximum_copy_size = audio_params_.time_to_bytes(range_for_block.length());
|
||||
int copied_size = 0;
|
||||
|
||||
// If the block is locked, we assume another thread has it. Otherwise, we'll work with it
|
||||
if (connected_output->has_cached_value(range_for_block)) {
|
||||
// This output already has this value, no need to process it again
|
||||
QByteArray samples_from_this_block = connected_output->get_cached_value(range_for_block).toByteArray();
|
||||
if (!samples_from_this_block.isEmpty()) {
|
||||
copied_size = samples_from_this_block.size();
|
||||
|
||||
int destination_offset = audio_params_.time_to_bytes(range_for_block.in() - range.in());
|
||||
|
||||
memcpy(block_range_buffer.data()+destination_offset,
|
||||
samples_from_this_block.data(),
|
||||
static_cast<size_t>(samples_from_this_block.size()));
|
||||
|
||||
active_blocks.removeAt(i);
|
||||
i--;
|
||||
} else if (!b->IsProcessingLocked()) {
|
||||
if (block_for_this_thread == -1) {
|
||||
block_for_this_thread = i;
|
||||
} else {
|
||||
emit RequestSibling(NodeDependency(connected_output,
|
||||
range_for_block));
|
||||
}
|
||||
}
|
||||
memcpy(block_range_buffer.data()+destination_offset,
|
||||
samples_from_this_block.data(),
|
||||
static_cast<size_t>(copied_size));
|
||||
}
|
||||
|
||||
if (block_for_this_thread > -1) {
|
||||
Block* b = active_blocks.at(block_for_this_thread);
|
||||
TimeRange range_for_block(qMax(b->in(), range.in()),
|
||||
qMin(b->out(), range.out()));
|
||||
|
||||
RenderAsSibling(NodeDependency(static_cast<NodeOutput*>(b->GetParameterWithID(output->id())),
|
||||
range_for_block));
|
||||
} else {
|
||||
QThread::msleep(500);
|
||||
if (copied_size < maximum_copy_size) {
|
||||
memset(block_range_buffer.data()+destination_offset+copied_size,
|
||||
0,
|
||||
static_cast<size_t>(maximum_copy_size - copied_size));
|
||||
}
|
||||
|
||||
NodeValueTable::Merge({merged_table, table});
|
||||
}
|
||||
|
||||
return block_range_buffer;
|
||||
}
|
||||
merged_table.Push(NodeParam::kSamples, block_range_buffer);
|
||||
|
||||
FramePtr AudioRenderWorker::RetrieveFromDecoder(DecoderPtr decoder, const TimeRange &range)
|
||||
{
|
||||
return decoder->RetrieveAudio(range.in(), range.out() - range.in(), audio_params_);
|
||||
return merged_table;
|
||||
}
|
||||
|
||||
@@ -11,18 +11,15 @@ public:
|
||||
|
||||
void SetParameters(const AudioRenderingParams& audio_params);
|
||||
|
||||
public slots:
|
||||
virtual QVariant RenderAsSibling(NodeDependency dep) override;
|
||||
|
||||
protected:
|
||||
virtual bool InitInternal() override;
|
||||
|
||||
virtual void CloseInternal() override;
|
||||
|
||||
QVariant RenderBlock(NodeOutput *output, const TimeRange& range);
|
||||
|
||||
virtual FramePtr RetrieveFromDecoder(DecoderPtr decoder, const TimeRange& range) override;
|
||||
|
||||
virtual NodeValueTable RenderBlock(NodeOutput *output, const TimeRange& range) override;
|
||||
|
||||
private:
|
||||
AudioRenderingParams audio_params_;
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ void OpenGLWorker::ParametersChangedEvent()
|
||||
}
|
||||
}
|
||||
|
||||
QVariant OpenGLWorker::RunNodeAccelerated(NodeOutput *out)
|
||||
NodeValueTable OpenGLWorker::RunNodeAccelerated(NodeOutput *out)
|
||||
{
|
||||
OpenGLShaderPtr shader = shader_cache_->GetShader(out);
|
||||
Node* node = out->parentNode();
|
||||
|
||||
@@ -49,7 +49,7 @@ protected:
|
||||
|
||||
virtual bool OutputIsAccelerated(NodeOutput *output) override;
|
||||
|
||||
virtual QVariant RunNodeAccelerated(NodeOutput *output) override;
|
||||
virtual NodeValueTable RunNodeAccelerated(NodeOutput *output) override;
|
||||
|
||||
virtual void TextureToBuffer(const QVariant& texture, QByteArray& buffer) override;
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ RenderWorker::RenderWorker(DecoderCache *decoder_cache, QObject *parent) :
|
||||
started_(false),
|
||||
decoder_cache_(decoder_cache)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool RenderWorker::IsAvailable()
|
||||
@@ -40,9 +39,36 @@ void RenderWorker::Close()
|
||||
|
||||
void RenderWorker::Render(NodeDependency path)
|
||||
{
|
||||
RenderInternal(path);
|
||||
emit CompletedCache(path, RenderInternal(path));
|
||||
}
|
||||
|
||||
emit CompletedCache(path);
|
||||
NodeValueTable RenderWorker::RenderAsSibling(NodeDependency dep)
|
||||
{
|
||||
NodeOutput* output = dep.node();
|
||||
Node* node = output->parentNode();
|
||||
QList<NodeInput*> connected_inputs;
|
||||
NodeValueTable value;
|
||||
|
||||
// Set working state
|
||||
working_++;
|
||||
|
||||
// Firstly we check if this node is a "Block", if it is that means it's part of a linked list of mutually exclusive
|
||||
// nodes based on time and we might need to locate which Block to attach to
|
||||
if (node->IsBlock()
|
||||
&& (dep.range().in() < static_cast<Block*>(node)->in()
|
||||
|| dep.range().out() > static_cast<Block*>(node)->out())) {
|
||||
// If the range is not wholly contained in this Block, we'll need to do some extra processing
|
||||
value = RenderBlock(output, dep.range());
|
||||
} else {
|
||||
value = ProcessNodeNormally(NodeDependency(output, dep.range()));
|
||||
}
|
||||
|
||||
// We're done!
|
||||
|
||||
// End this working state
|
||||
working_--;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
DecoderCache *RenderWorker::decoder_cache()
|
||||
@@ -93,9 +119,9 @@ QList<Block *> RenderWorker::ValidateBlockRange(Block *n, const TimeRange &range
|
||||
return list;
|
||||
}
|
||||
|
||||
void RenderWorker::RenderInternal(const NodeDependency &path)
|
||||
NodeValueTable RenderWorker::RenderInternal(const NodeDependency &path)
|
||||
{
|
||||
RenderAsSibling(path);
|
||||
return RenderAsSibling(path);
|
||||
}
|
||||
|
||||
StreamPtr RenderWorker::ResolveStreamFromInput(NodeInput *input)
|
||||
@@ -124,116 +150,35 @@ bool RenderWorker::IsStarted()
|
||||
return started_;
|
||||
}
|
||||
|
||||
QList<NodeInput*> RenderWorker::ProcessNodeInputsForTime(Node *n, const TimeRange &time)
|
||||
{
|
||||
QList<NodeInput*> connected_inputs;
|
||||
|
||||
// Now we need to gather information about this Node's inputs
|
||||
foreach (NodeParam* param, n->parameters()) {
|
||||
// Check if this parameter is an input and if the Node is dependent on it
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
|
||||
if (input->dependent()) {
|
||||
// If we're here, this input is necessary and we need to acquire the value for this Node
|
||||
if (input->IsConnected()) {
|
||||
// If it's connected to something, we need to retrieve that output at some point
|
||||
connected_inputs.append(input);
|
||||
} else {
|
||||
// If it isn't connected, it'll have the value we need inside it. We just need to store it for the node.
|
||||
input->set_stored_value(input->get_value_at_time(n->InputTimeAdjustment(input, time).in()));
|
||||
}
|
||||
|
||||
// Special types like FOOTAGE require extra work from us (to decrease node complexity dealing with decoders)
|
||||
if (input->data_type() == NodeParam::kFootage) {
|
||||
input->set_stored_value(0);
|
||||
|
||||
DecoderPtr decoder = ResolveDecoderFromInput(input);
|
||||
|
||||
// By this point we should definitely have a decoder, and if we don't something's gone terribly wrong
|
||||
if (decoder != nullptr) {
|
||||
FramePtr frame = RetrieveFromDecoder(decoder, time);
|
||||
|
||||
if (frame != nullptr) {
|
||||
QVariant value = FrameToValue(frame);
|
||||
|
||||
input->set_stored_value(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return connected_inputs;
|
||||
}
|
||||
|
||||
QVariant RenderWorker::ProcessNodeNormally(const NodeDependency& dep)
|
||||
NodeValueTable RenderWorker::ProcessNodeNormally(const NodeDependency& dep)
|
||||
{
|
||||
NodeOutput* output = dep.node();
|
||||
Node* node = dep.node()->parentNode();
|
||||
|
||||
//qDebug() << "Processing" << node->id();
|
||||
|
||||
// Check if the output already has a value for this time
|
||||
if (output->has_cached_value(dep.range())) {
|
||||
// If so, we don't need to do anything, we can just send this value and exit here
|
||||
return output->get_cached_value(dep.range());
|
||||
}
|
||||
// FIXME: Cache certain values here if we've already processed them before
|
||||
|
||||
// We need to run the Node's code to get the correct value for this time
|
||||
NodeValueDatabase database;
|
||||
|
||||
QList<NodeInput*> connected_inputs = ProcessNodeInputsForTime(node, dep.range());
|
||||
|
||||
// For each connected input, we need to acquire the value from another node
|
||||
while (!connected_inputs.isEmpty()) {
|
||||
|
||||
// Remove any inputs from the list that we have valid cached values for already
|
||||
for (int i=0;i<connected_inputs.size();i++) {
|
||||
NodeInput* input = connected_inputs.at(i);
|
||||
NodeOutput* connected_output = input->get_connected_output();
|
||||
// We need to insert tables into the database for each input
|
||||
foreach (NodeParam* param, node->parameters()) {
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
NodeValueTable table;
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
TimeRange input_time = node->InputTimeAdjustment(input, dep.range());
|
||||
|
||||
if (connected_output->has_cached_value(input_time)) {
|
||||
// This output already has this value, no need to process it again
|
||||
input->set_stored_value(connected_output->get_cached_value(input_time));
|
||||
connected_inputs.removeAt(i);
|
||||
i--;
|
||||
if (input->IsConnected()) {
|
||||
// Value will equal something from the connected node, follow it
|
||||
table = ProcessNodeNormally(NodeDependency(input->get_connected_output(),
|
||||
input_time));
|
||||
} else {
|
||||
// Push onto the table the value at this time from the input
|
||||
QVariant input_value = input->get_value_at_time(input_time.in());
|
||||
table.Push(input->data_type(), input_value);
|
||||
}
|
||||
}
|
||||
|
||||
// For every connected input except the first, we'll request another Node to do it
|
||||
int input_for_this_thread = -1;
|
||||
|
||||
for (int i=0;i<connected_inputs.size();i++) {
|
||||
NodeInput* input = connected_inputs.at(i);
|
||||
|
||||
// If this node is locked, we assume it's already being processed. Otherwise we need to request a sibling
|
||||
if (!input->get_connected_node()->IsProcessingLocked()) {
|
||||
if (input_for_this_thread == -1) {
|
||||
// Store this later since we can process it on this thread as we wait for other threads
|
||||
input_for_this_thread = i;
|
||||
} else {
|
||||
TimeRange input_time = node->InputTimeAdjustment(input, dep.range());
|
||||
|
||||
emit RequestSibling(NodeDependency(input->get_connected_output(),
|
||||
input_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (input_for_this_thread > -1) {
|
||||
// In the mean time, this thread can go off to do the first parameter
|
||||
NodeInput* input = connected_inputs.at(input_for_this_thread);
|
||||
TimeRange input_range = node->InputTimeAdjustment(input, dep.range());
|
||||
RenderAsSibling(NodeDependency(input->get_connected_output(),
|
||||
input_range));
|
||||
input->set_stored_value(input->get_connected_output()->get_cached_value(input_range));
|
||||
connected_inputs.removeAt(input_for_this_thread);
|
||||
} else {
|
||||
// Nothing for this thread to do. We'll wait 0.5 sec and check again for other nodes
|
||||
// FIXME: It would be nicer if this thread could do other nodes during this time
|
||||
QThread::msleep(500);
|
||||
database.Insert(input, table);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +190,6 @@ QVariant RenderWorker::ProcessNodeNormally(const NodeDependency& dep)
|
||||
return RunNodeAccelerated(output);
|
||||
} else {
|
||||
// Generate the value as expected
|
||||
return node->Value(output);
|
||||
return node->Value(database);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,12 +27,12 @@ public slots:
|
||||
|
||||
void Render(NodeDependency path);
|
||||
|
||||
virtual QVariant RenderAsSibling(NodeDependency dep) = 0;
|
||||
NodeValueTable RenderAsSibling(NodeDependency dep);
|
||||
|
||||
signals:
|
||||
void RequestSibling(NodeDependency path);
|
||||
|
||||
void CompletedCache(NodeDependency dep);
|
||||
void CompletedCache(NodeDependency dep, NodeValueTable data);
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -64,22 +64,22 @@ protected:
|
||||
|
||||
virtual void CloseInternal() = 0;
|
||||
|
||||
virtual void RenderInternal(const NodeDependency& path);
|
||||
virtual NodeValueTable RenderInternal(const NodeDependency& path);
|
||||
|
||||
virtual bool OutputIsAccelerated(NodeOutput *output) = 0;
|
||||
|
||||
virtual QVariant RunNodeAccelerated(NodeOutput *output) = 0;
|
||||
virtual NodeValueTable RunNodeAccelerated(NodeOutput *output) = 0;
|
||||
|
||||
StreamPtr ResolveStreamFromInput(NodeInput* input);
|
||||
DecoderPtr ResolveDecoderFromInput(NodeInput* input);
|
||||
|
||||
virtual FramePtr RetrieveFromDecoder(DecoderPtr decoder, const TimeRange& range) = 0;
|
||||
|
||||
QList<NodeInput*> ProcessNodeInputsForTime(Node* n, const TimeRange& time);
|
||||
|
||||
virtual QVariant FrameToValue(FramePtr frame) = 0;
|
||||
|
||||
QVariant ProcessNodeNormally(const NodeDependency &dep);
|
||||
NodeValueTable ProcessNodeNormally(const NodeDependency &dep);
|
||||
|
||||
virtual NodeValueTable RenderBlock(NodeOutput *output, const TimeRange& range) = 0;
|
||||
|
||||
DecoderCache* decoder_cache();
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const VideoRenderingParams &VideoRenderWorker::video_params()
|
||||
return video_params_;
|
||||
}
|
||||
|
||||
void VideoRenderWorker::RenderInternal(const NodeDependency& path)
|
||||
NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path)
|
||||
{
|
||||
// Get hash of node graph
|
||||
// We use SHA-1 for speed (benchmarks show it's the fastest hash available to us)
|
||||
@@ -24,18 +24,22 @@ void VideoRenderWorker::RenderInternal(const NodeDependency& path)
|
||||
HashNodeRecursively(&hasher, path.node()->parentNode(), path.in());
|
||||
QByteArray hash = hasher.result();
|
||||
|
||||
NodeValueTable value;
|
||||
|
||||
if (frame_cache_->HasHash(hash)) {
|
||||
// We've already cached this hash, no need to continue
|
||||
emit HashAlreadyExists(path, hash);
|
||||
} else if (frame_cache_->TryCache(hash)) {
|
||||
// This hash is available for us to cache, start traversing graph
|
||||
QVariant value = RenderAsSibling(path);
|
||||
value = RenderAsSibling(path);
|
||||
|
||||
emit CompletedFrame(path, hash, value);
|
||||
} else {
|
||||
// Another thread must be caching this already, nothing to be done
|
||||
emit HashAlreadyBeingCached();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
FramePtr VideoRenderWorker::RetrieveFromDecoder(DecoderPtr decoder, const TimeRange &range)
|
||||
@@ -120,42 +124,6 @@ void VideoRenderWorker::CloseInternal()
|
||||
download_buffer_.clear();
|
||||
}
|
||||
|
||||
QVariant VideoRenderWorker::RenderAsSibling(NodeDependency dep)
|
||||
{
|
||||
NodeOutput* output = dep.node();
|
||||
Node* original_node = output->parentNode();
|
||||
Node* node;
|
||||
rational time = dep.in();
|
||||
QVariant value;
|
||||
|
||||
// Set working state
|
||||
working_++;
|
||||
|
||||
//qDebug() << "Processing" << original_node->id() << original_node;
|
||||
|
||||
// Firstly we check if this node is a "Block", if it is that means it's part of a linked list of mutually exclusive
|
||||
// nodes based on time and we might need to locate which Block to attach to
|
||||
if (original_node->IsBlock()) {
|
||||
node = ValidateBlock(static_cast<Block*>(original_node), time);
|
||||
|
||||
if (original_node != node) {
|
||||
// Ensure output is the output matching the node as it may have changed
|
||||
output = static_cast<NodeOutput*>(node->GetParameterWithID(output->id()));
|
||||
}
|
||||
} else {
|
||||
node = original_node;
|
||||
}
|
||||
|
||||
value = ProcessNodeNormally(NodeDependency(output, dep.range()));
|
||||
|
||||
// We're done!
|
||||
|
||||
// End this working state
|
||||
working_--;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void VideoRenderWorker::Download(NodeDependency dep, QByteArray hash, QVariant texture, QString filename)
|
||||
{
|
||||
working_++;
|
||||
@@ -184,3 +152,18 @@ void VideoRenderWorker::Download(NodeDependency dep, QByteArray hash, QVariant t
|
||||
|
||||
working_--;
|
||||
}
|
||||
|
||||
NodeValueTable VideoRenderWorker::RenderBlock(NodeOutput* output, const TimeRange &range)
|
||||
{
|
||||
// A frame can only have one active block so we just validate the in point of the range
|
||||
Block* active_block = ValidateBlock(static_cast<Block*>(output->parentNode()), range.in());
|
||||
|
||||
NodeValueTable table;
|
||||
|
||||
if (active_block) {
|
||||
table = RenderAsSibling(NodeDependency(active_block->block_output(),
|
||||
range));
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,10 @@ public:
|
||||
void SetParameters(const VideoRenderingParams& video_params);
|
||||
|
||||
public slots:
|
||||
virtual QVariant RenderAsSibling(NodeDependency dep) override;
|
||||
|
||||
void Download(NodeDependency dep, QByteArray hash, QVariant texture, QString filename);
|
||||
|
||||
signals:
|
||||
void CompletedFrame(NodeDependency path, QByteArray hash, QVariant value);
|
||||
void CompletedFrame(NodeDependency path, QByteArray hash, NodeValueTable value);
|
||||
|
||||
void CompletedDownload(NodeDependency path, QByteArray hash);
|
||||
|
||||
@@ -40,10 +38,12 @@ protected:
|
||||
|
||||
virtual void TextureToBuffer(const QVariant& texture, QByteArray& buffer) = 0;
|
||||
|
||||
virtual void RenderInternal(const NodeDependency& path) override;
|
||||
virtual NodeValueTable RenderInternal(const NodeDependency& path) override;
|
||||
|
||||
virtual FramePtr RetrieveFromDecoder(DecoderPtr decoder, const TimeRange& range) override;
|
||||
|
||||
virtual NodeValueTable RenderBlock(NodeOutput *output, const TimeRange& range) override;
|
||||
|
||||
private:
|
||||
void ProcessNode();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user