shift renderer prototype to new node structure

This commit is contained in:
itsmattkc
2019-08-28 02:40:44 +10:00
parent 5afe7d523c
commit 7dc2290496
26 changed files with 264 additions and 395 deletions
@@ -16,12 +16,8 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/processor/renderer/renderpath.h
node/processor/renderer/renderpath.cpp
node/processor/renderer/renderer.h
node/processor/renderer/renderer.cpp
node/processor/renderer/rendererprobe.h
node/processor/renderer/rendererprobe.cpp
node/processor/renderer/rendererthread.h
node/processor/renderer/rendererthread.cpp
PARENT_SCOPE
+15 -45
View File
@@ -27,9 +27,6 @@
#include <QImage>
#include <QtMath>
#include "renderpath.h"
#include "rendererprobe.h"
RendererProcessor::RendererProcessor() :
started_(false),
width_(0),
@@ -208,6 +205,7 @@ void RendererProcessor::Start()
// Ensure this connection is "Queued" so that it always runs in this object's threaded rather than any of the
// other threads
connect(threads_[i].get(), SIGNAL(FinishedPath()), this, SLOT(ThreadCallback()), Qt::QueuedConnection);
connect(threads_[i].get(), SIGNAL(RequestSibling(NodeDependency)), this, SLOT(ThreadRequestSibling(NodeDependency)), Qt::QueuedConnection);
}
started_ = true;
@@ -259,44 +257,11 @@ void RendererProcessor::CacheNext()
qDebug() << "Caching" << time_to_cache.toDouble();
Node* node_to_cache = texture_input_->edges().first()->output()->parent();
// Set graph time
//node_to_cache->set_time(time_to_cache);
// Run this probe in another thread
RenderPath path = RendererProbe::ProbeNode(node_to_cache, threads_.size(), time_to_cache);
cache_return_count_ = 0;
for (int i=0;i<threads_.size();i++) {
threads_.at(i)->Queue(path.GetThreadPath(i), time_to_cache);
}
master_thread_ = threads_.at(0).get();
master_thread_->Queue(NodeDependency(texture_input_->get_connected_output(), time_to_cache), true);
caching_ = true;
/*
bool caching = false;
// Look for a thread that's available
for (int i=0;i<threads_.size();i++) {
RendererThreadPtr thread = threads_.at(i);
if (thread->Queue(node_to_cache, time_to_cache)) {
// This thread is free and we've just taken control of it
caching = true;
break;
}
}
if (caching) {
cache_queue_.removeFirst();
qDebug() << "[RendererProcessor] Ready to cache" << time_to_cache.numerator() << "/" << time_to_cache.denominator();
}
*/
}
// FIXME: Test code only
@@ -305,21 +270,26 @@ void RendererProcessor::CacheNext()
void RendererProcessor::ThreadCallback()
{
cache_return_count_++;
if (cache_return_count_ == threads_.size()) {
if (sender() == master_thread_) {
// Threads are all done now, time to proceed
caching_ = false;
// FIXME: Test code only
// Signal update to viewer
static_cast<ViewerOutput*>(texture_output()->edges().first()->input()->parent())->InvalidateCache(0, 0);
// End test code
// FIXME: Save the texture results here
CacheNext();
}
}
void RendererProcessor::ThreadRequestSibling(NodeDependency dep)
{
// Try to queue another thread to run this dep in advance
for (int i=0;i<threads_.size();i++) {
if (threads_.at(i)->Queue(dep, false)) {
return;
}
}
}
RendererThread* RendererProcessor::CurrentThread()
{
return dynamic_cast<RendererThread*>(QThread::currentThread());
+3 -1
View File
@@ -149,11 +149,13 @@ private:
qint64 cache_time_;
QString cache_id_;
bool caching_;
int cache_return_count_;
RendererThread* master_thread_;
private slots:
void ThreadCallback();
void ThreadRequestSibling(NodeDependency dep);
};
#endif // RENDERER_H
@@ -1,86 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "rendererprobe.h"
#include <QDebug>
RendererProbe::RendererProbe()
{
}
RenderPath RendererProbe::ProbeNode(Node *node, int thread_count, const rational& time)
{
Q_ASSERT(thread_count > 0);
RenderPath render_path(thread_count);
TraverseNode(render_path, node, time, 0, 0);
render_path.Finalize();
return render_path;
}
void RendererProbe::TraverseNode(RenderPath& path, Node *node, const rational& time, int thread, int index)
{
Q_UNUSED(path)
Q_UNUSED(node)
Q_UNUSED(time)
Q_UNUSED(thread)
Q_UNUSED(index)
/*bool can_take_node = true;
if (path.ContainsNode(node) >= 0) {
if (path.NodeIndex(node) < index) {
// If the other thread's index is smaller, it means we can do it earlier here so we should "steal" it
qDebug() << "Stealing" << node << "to" << thread;
path.RemoveEntry(node);
} else {
// Otherwise, we'll be delaying it and there's no point to that
can_take_node = false;
}
}
// Add this node to the thread path
if (can_take_node) {
qDebug() << node << "will run on thread" << thread << "at index" << index;
path.AddEntry(node, thread, index);
}
QList<Node*> deps = node->RunDependencies(nullptr, time);
// Print debugging information
foreach (Node* dep, deps) {
qDebug() << " Dependency found:" << dep;
}
int next_index = index + 1;
foreach (Node* dep, deps) {
int ideal_thread = path.FindAvailableThreadAtIndex(index);
// FIXME: This will throw this thread's index off by one, test whether this is okay
int run_thread = (ideal_thread == -1) ? thread : ideal_thread;
TraverseNode(path, dep, time, run_thread, next_index);
}*/
}
@@ -1,39 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef RENDERERPROBE_H
#define RENDERERPROBE_H
#include "node/node.h"
#include "renderpath.h"
class RendererProbe
{
public:
RendererProbe();
static RenderPath ProbeNode(Node* node, int thread_count, const rational &time);
private:
static void TraverseNode(RenderPath& path, Node* node, const rational& time, int thread, int index);
};
#endif // RENDERERPROBE_H
+24 -10
View File
@@ -33,14 +33,17 @@ RendererThread::RendererThread(QOpenGLContext *share_ctx, const int &width, cons
{
}
void RendererThread::Queue(const RenderThreadPath &path, const rational& time)
bool RendererThread::Queue(const NodeDependency& dep, bool wait)
{
// Wait for thread to be available
mutex_.lock();
if (wait) {
// Wait for thread to be available
mutex_.lock();
} else if (!mutex_.tryLock()) {
return false;
}
// We can now change params without the other thread using them
path_ = path;
time_ = time;
path_ = dep;
// Prepare to wait for thread to respond
caller_mutex_.lock();
@@ -52,6 +55,8 @@ void RendererThread::Queue(const RenderThreadPath &path, const rational& time)
// Wait for thread to start before returning
wait_cond_.wait(&caller_mutex_);
caller_mutex_.unlock();
return true;
}
void RendererThread::Cancel()
@@ -97,9 +102,20 @@ void RendererThread::run()
caller_mutex_.unlock();
// Process the Node
/*for (int i=path_.size()-1;i>=0;i--) {
path_.at(i)->Run();
}*/
NodeOutput* output_to_process = path_.node();
Node* node_to_process = output_to_process->parent();
QList<NodeDependency> deps = node_to_process->RunDependencies(output_to_process, path_.time());
// Ask for other threads to run these deps while we're here
if (!deps.isEmpty()) {
for (int i=1;i<deps.size();i++) {
emit RequestSibling(deps.at(i));
}
}
// Get the requested value
output_to_process->get_value(path_.time());
emit FinishedPath();
}
@@ -115,8 +131,6 @@ void RendererThread::run()
void RendererThread::StartThread(QThread::Priority priority)
{
path_.clear();
caller_mutex_.lock();
// Start the thread
+4 -3
View File
@@ -28,7 +28,6 @@
#include "node/node.h"
#include "render/renderinstance.h"
#include "renderpath.h"
class RendererThread : public QThread
{
@@ -40,7 +39,7 @@ public:
const olive::PixelFormat& format,
const olive::RenderMode& mode);
void Queue(const RenderThreadPath& path, const rational &time);
bool Queue(const NodeDependency &dep, bool wait);
void Cancel();
@@ -51,6 +50,8 @@ public:
void StartThread(Priority priority = InheritPriority);
signals:
void RequestSibling(NodeDependency dep);
void FinishedPath();
private:
@@ -62,7 +63,7 @@ private:
QMutex caller_mutex_;
RenderThreadPath path_;
NodeDependency path_;
rational time_;
@@ -1,88 +0,0 @@
#include "renderpath.h"
RenderPath::RenderPath(int max_threads) :
finalized_(false)
{
Q_ASSERT(max_threads > 0);
render_path_.resize(max_threads);
}
void RenderPath::AddEntry(Node *node, int thread, int index)
{
if (finalized_) {
return;
}
RenderThreadPath& thread_path = render_path_[thread];
// Make sure there are enough indices for this entry
while (thread_path.size() < index) {
thread_path.append(nullptr);
}
thread_path.append(node);
thread_map_.insert(node, thread);
}
void RenderPath::RemoveEntry(Node *node)
{
if (finalized_) {
return;
}
Q_ASSERT(thread_map_.contains(node));
int node_thread = thread_map_[node];
render_path_[node_thread].replace(NodeIndexInThread(node, node_thread), nullptr);
thread_map_.remove(node);
}
int RenderPath::ContainsNode(Node *node)
{
if (thread_map_.contains(node)) {
return thread_map_[node];
}
return -1;
}
int RenderPath::NodeIndex(Node *node)
{
if (thread_map_.contains(node)) {
return NodeIndexInThread(node, thread_map_[node]);
}
return -1;
}
int RenderPath::NodeIndexInThread(Node *node, int thread)
{
return render_path_[thread].indexOf(node);
}
void RenderPath::Finalize()
{
for (int i=0;i<render_path_.size();i++) {
render_path_[i].removeAll(nullptr);
}
finalized_ = true;
}
int RenderPath::FindAvailableThreadAtIndex(int index)
{
for (int i=0;i<render_path_.size();i++) {
QVector<Node*>& thread_path_ = render_path_[i];
if (index >= thread_path_.size() || thread_path_.at(index) == nullptr) {
return i;
}
}
return -1;
}
RenderThreadPath &RenderPath::GetThreadPath(int thread)
{
return render_path_[thread];
}
-82
View File
@@ -1,82 +0,0 @@
#ifndef RENDERPATH_H
#define RENDERPATH_H
#include <QVector>
#include "node/node.h"
using RenderThreadPath = QVector<Node*>;
class RenderPath
{
public:
RenderPath(int max_threads);
/**
* @brief Add a Node to this thread at this index
*
* The Node is guaranteed to be added to at least this index. The index may be higher if this thread has other Nodes
* taking up this index, but it will never be lower.
*/
void AddEntry(Node* node, int thread, int index);
/**
* @brief Removes a Node, replacing its entry with nullptr
*
* This function asserts whether the Node was added initially to help aid bug detection.
*
* @param node
*/
void RemoveEntry(Node* node);
/**
* @brief Determine whether the RenderPath already contains this Node
*
* @return
*
* The thread index if one contains this Node, or -1 if none of them do
*/
int ContainsNode(Node* node);
/**
* @brief Determine what index a Node has in whatever thread it's in
*
* @return
*
* The Node's index in its thread, or -1 if no threads have this Node.
*/
int NodeIndex(Node* node);
/**
* @brief Determine what index a Node has in a particular thread
*
* @return
*
* The Node's index in this thread, or -1 if this thread does not have this Node.
*/
int NodeIndexInThread(Node* node, int thread);
/**
* @brief Finalize the render path ready for executing
*
* Probing uses indices to determine what Nodes occur where. Depending on the state of the graph, many of these
* indices will be empty across all the threads which, while helpful for probing, is unnecessary for executing.
* Running this function assumes no further probing will occur.
*
* Finalizing places this RenderPath into more-or-less a read-only state.
*/
void Finalize();
int FindAvailableThreadAtIndex(int index);
RenderThreadPath& GetThreadPath(int thread);
private:
QVector<RenderThreadPath> render_path_;
QMap<Node*, int> thread_map_;
bool finalized_;
};
#endif // RENDERPATH_H