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:
itsmattkc
2019-12-05 03:53:52 +11:00
parent 88c3bd44a5
commit f424d8b44e
14 changed files with 154 additions and 263 deletions
+49 -104
View File
@@ -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);
}
}