completed prototype of background service that traverse the graph
This commit is contained in:
@@ -218,6 +218,7 @@ void Core::CreateNewFolder()
|
||||
}
|
||||
|
||||
// FIXME: Test code
|
||||
#include "node/blend/alphaover/alphaover.h"
|
||||
#include "node/output/timeline/timeline.h"
|
||||
#include "node/output/track/track.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
@@ -303,6 +304,11 @@ void Core::CreateNewSequence()
|
||||
// Connect track to timeline
|
||||
NodeParam::ConnectEdge(to->track_output(), tb->track_input());
|
||||
|
||||
// FIXME: Test code
|
||||
AlphaOverBlend* blend = new AlphaOverBlend();
|
||||
new_sequence->AddNode(blend);
|
||||
// End test code
|
||||
|
||||
vo->AttachViewer(olive::panel_focus_manager->MostRecentlyFocused<ViewerPanel>());
|
||||
tb->AttachTimeline(olive::panel_focus_manager->MostRecentlyFocused<TimelinePanel>());
|
||||
olive::panel_focus_manager->MostRecentlyFocused<NodePanel>()->SetGraph(new_sequence.get());
|
||||
|
||||
@@ -1,10 +1,27 @@
|
||||
#include "alphaover.h"
|
||||
|
||||
#include "render/rendertypes.h"
|
||||
|
||||
AlphaOverBlend::AlphaOverBlend()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString AlphaOverBlend::Name()
|
||||
{
|
||||
return tr("Alpha Over");
|
||||
}
|
||||
|
||||
QString AlphaOverBlend::id()
|
||||
{
|
||||
return "org.olivevideoeditor.Olive.alphaoverblend";
|
||||
}
|
||||
|
||||
QString AlphaOverBlend::Description()
|
||||
{
|
||||
return tr("A blending node that composites one texture over another using its alpha channel.");
|
||||
}
|
||||
|
||||
void AlphaOverBlend::Process(const rational &time)
|
||||
{
|
||||
Q_UNUSED(time)
|
||||
@@ -13,5 +30,10 @@ void AlphaOverBlend::Process(const rational &time)
|
||||
|
||||
// Note that alpha will always be premultiplied by this point
|
||||
|
||||
|
||||
|
||||
//GLuint base_tex = base_input_->get_value(time).value<GLuint>();
|
||||
|
||||
// FIXME: Does nothing
|
||||
texture_output()->set_value(blend_input()->get_value(time).value<RenderTexture>());
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ class AlphaOverBlend : public BlendNode
|
||||
public:
|
||||
AlphaOverBlend();
|
||||
|
||||
virtual QString Name() override;
|
||||
virtual QString id() override;
|
||||
virtual QString Description() override;
|
||||
|
||||
protected:
|
||||
virtual void Process(const rational &time) override;
|
||||
};
|
||||
|
||||
@@ -9,6 +9,15 @@ BlendNode::BlendNode()
|
||||
blend_input_ = new NodeInput("blend_in");
|
||||
blend_input_->add_data_input(NodeParam::kTexture);
|
||||
AddParameter(blend_input_);
|
||||
|
||||
texture_output_ = new NodeOutput("tex_out");
|
||||
texture_output_->set_data_type(NodeParam::kTexture);
|
||||
AddParameter(texture_output_);
|
||||
}
|
||||
|
||||
QString BlendNode::Category()
|
||||
{
|
||||
return tr("Blend");
|
||||
}
|
||||
|
||||
NodeInput *BlendNode::base_input()
|
||||
@@ -20,3 +29,8 @@ NodeInput *BlendNode::blend_input()
|
||||
{
|
||||
return blend_input_;
|
||||
}
|
||||
|
||||
NodeOutput *BlendNode::texture_output()
|
||||
{
|
||||
return texture_output_;
|
||||
}
|
||||
|
||||
@@ -8,14 +8,20 @@ class BlendNode : public Node
|
||||
public:
|
||||
BlendNode();
|
||||
|
||||
virtual QString Category() override;
|
||||
|
||||
NodeInput* base_input();
|
||||
|
||||
NodeInput* blend_input();
|
||||
|
||||
NodeOutput* texture_output();
|
||||
|
||||
private:
|
||||
NodeInput* base_input_;
|
||||
|
||||
NodeInput* blend_input_;
|
||||
|
||||
NodeOutput* texture_output_;
|
||||
};
|
||||
|
||||
#endif // BLEND_H
|
||||
|
||||
@@ -111,6 +111,9 @@ QList<Node *> TrackOutput::GetImmediateDependenciesAt(const rational &time)
|
||||
nodes.append(current_block_);
|
||||
}
|
||||
|
||||
// The next track is not a direct dependency (it would only become so through a merge node)
|
||||
nodes.removeAll(next_track());
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +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
|
||||
|
||||
@@ -27,12 +27,14 @@
|
||||
#include <QtMath>
|
||||
|
||||
#include "render/rendertypes.h"
|
||||
#include "renderpath.h"
|
||||
#include "rendererprobe.h"
|
||||
|
||||
RendererProcessor::RendererProcessor() :
|
||||
started_(false),
|
||||
width_(0),
|
||||
height_(0)
|
||||
height_(0),
|
||||
caching_(false)
|
||||
{
|
||||
texture_input_ = new NodeInput("tex_in");
|
||||
texture_input_->add_data_input(NodeInput::kTexture);
|
||||
@@ -145,13 +147,15 @@ void RendererProcessor::InvalidateCache(const rational &start_range, const ratio
|
||||
<< "and"
|
||||
<< end_range.toDouble();
|
||||
|
||||
// FIXME: Snap start_range to timebase
|
||||
|
||||
for (rational r=start_range;r<=end_range;r+=timebase_) {
|
||||
if (!cache_queue_.contains(r)) {
|
||||
cache_queue_.append(r);
|
||||
}
|
||||
}
|
||||
|
||||
CacheCallback();
|
||||
CacheNext();
|
||||
|
||||
Node::InvalidateCache(start_range, end_range);
|
||||
}
|
||||
@@ -192,6 +196,10 @@ void RendererProcessor::Start()
|
||||
for (int i=0;i<threads_.size();i++) {
|
||||
threads_[i] = std::make_shared<RendererThread>(width_, height_, format_, mode_);
|
||||
threads_[i]->StartThread(QThread::HighPriority);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
started_ = true;
|
||||
@@ -230,21 +238,33 @@ void RendererProcessor::GenerateCacheIDInternal()
|
||||
cache_id_ = bytes.toHex();
|
||||
}
|
||||
|
||||
void RendererProcessor::CacheCallback()
|
||||
void RendererProcessor::CacheNext()
|
||||
{
|
||||
if (cache_queue_.isEmpty() || !texture_input_->IsConnected()) {
|
||||
if (cache_queue_.isEmpty() || !texture_input_->IsConnected() || caching_) {
|
||||
return;
|
||||
}
|
||||
|
||||
rational time_to_cache = cache_queue_.first();
|
||||
// Make sure cache has started
|
||||
Start();
|
||||
|
||||
rational time_to_cache = cache_queue_.takeFirst();
|
||||
|
||||
Node* node_to_cache = texture_input_->edges().first()->output()->parent();
|
||||
|
||||
RendererProbe::ProbeNode(node_to_cache, QThread::idealThreadCount(), 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++) {
|
||||
qDebug() << "Queued thread" << threads_.at(i).get();
|
||||
threads_.at(i)->Queue(path.GetThreadPath(i), time_to_cache);
|
||||
}
|
||||
|
||||
caching_ = true;
|
||||
|
||||
/*
|
||||
// Make sure cache has started
|
||||
Start();
|
||||
|
||||
|
||||
bool caching = false;
|
||||
|
||||
@@ -267,6 +287,18 @@ void RendererProcessor::CacheCallback()
|
||||
*/
|
||||
}
|
||||
|
||||
void RendererProcessor::ThreadCallback()
|
||||
{
|
||||
cache_return_count_++;
|
||||
|
||||
if (cache_return_count_ == threads_.size()) {
|
||||
// Threads are all done now, time to proceed
|
||||
caching_ = false;
|
||||
|
||||
CacheNext();
|
||||
}
|
||||
}
|
||||
|
||||
RendererThread* RendererProcessor::CurrentThread()
|
||||
{
|
||||
return dynamic_cast<RendererThread*>(QThread::currentThread());
|
||||
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
*
|
||||
* This function is NOT thread-safe and should only be called in the main thread.
|
||||
*/
|
||||
void CacheCallback();
|
||||
void CacheNext();
|
||||
|
||||
/**
|
||||
* @brief Internal list of RenderThreads
|
||||
@@ -148,6 +148,11 @@ private:
|
||||
QString cache_name_;
|
||||
qint64 cache_time_;
|
||||
QString cache_id_;
|
||||
bool caching_;
|
||||
int cache_return_count_;
|
||||
|
||||
private slots:
|
||||
void ThreadCallback();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/***
|
||||
|
||||
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>
|
||||
@@ -7,29 +27,55 @@ RendererProbe::RendererProbe()
|
||||
|
||||
}
|
||||
|
||||
void RendererProbe::ProbeNode(Node *node, int thread_count, const rational& time)
|
||||
RenderPath RendererProbe::ProbeNode(Node *node, int thread_count, const rational& time)
|
||||
{
|
||||
Q_ASSERT(thread_count > 0);
|
||||
|
||||
//QVector< QVector<Node*> > dependency_graph;
|
||||
RenderPath render_path(thread_count);
|
||||
|
||||
//dependency_graph.resize(thread_count);
|
||||
TraverseNode(render_path, node, time, 0, 0);
|
||||
|
||||
TraverseNode(node, 0, time);
|
||||
render_path.Finalize();
|
||||
|
||||
return render_path;
|
||||
}
|
||||
|
||||
void RendererProbe::TraverseNode(Node *node, int thread, const rational& time)
|
||||
void RendererProbe::TraverseNode(RenderPath& path, Node *node, const rational& time, int thread, int index)
|
||||
{
|
||||
qDebug() << node << "will run on thread" << thread;
|
||||
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->GetImmediateDependenciesAt(time);
|
||||
|
||||
// Print debugging information
|
||||
foreach (Node* dep, deps) {
|
||||
qDebug() << " Dependency found:" << dep;
|
||||
}
|
||||
|
||||
int next_index = index + 1;
|
||||
|
||||
foreach (Node* dep, deps) {
|
||||
TraverseNode(dep, thread, time);
|
||||
thread++;
|
||||
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,17 +1,39 @@
|
||||
/***
|
||||
|
||||
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 void ProbeNode(Node* node, int thread_count, const rational &time);
|
||||
static RenderPath ProbeNode(Node* node, int thread_count, const rational &time);
|
||||
|
||||
private:
|
||||
static void TraverseNode(Node* node, int thread, const rational& time);
|
||||
static void TraverseNode(RenderPath& path, Node* node, const rational& time, int thread, int index);
|
||||
|
||||
};
|
||||
|
||||
#endif // RENDERERPROBE_H
|
||||
|
||||
@@ -32,33 +32,25 @@ RendererThread::RendererThread(const int &width, const int &height, const olive:
|
||||
{
|
||||
}
|
||||
|
||||
bool RendererThread::Queue(Node *n, const rational& time)
|
||||
void RendererThread::Queue(const RenderThreadPath &path, const rational& time)
|
||||
{
|
||||
// If the thread is inactive, tryLock() will succeed
|
||||
if (mutex_.tryLock()) {
|
||||
// Wait for thread to be available
|
||||
mutex_.lock();
|
||||
|
||||
qDebug() << "[RendererThread Main] tryLock succeeded";
|
||||
// We can now change params without the other thread using them
|
||||
path_ = path;
|
||||
time_ = time;
|
||||
|
||||
// The mutex is locked in the calling thread now, so we can change the active Node
|
||||
node_ = n;
|
||||
time_ = time;
|
||||
// Prepare to wait for thread to respond
|
||||
caller_mutex_.lock();
|
||||
|
||||
// We can now wake up our main thread
|
||||
qDebug() << "[RendererThread Main] Waking thread";
|
||||
wait_cond_.wakeAll();
|
||||
qDebug() << "[RendererThread Main] Unlocking mutex";
|
||||
mutex_.unlock();
|
||||
// Wake up our main thread
|
||||
wait_cond_.wakeAll();
|
||||
mutex_.unlock();
|
||||
|
||||
// Wait for thread to start before returning
|
||||
qDebug() << "[RendererThread Main] Waiting for caller mutex";
|
||||
caller_mutex_.lock();
|
||||
qDebug() << "[RendererThread Main] Caller mutex arrived";
|
||||
caller_mutex_.unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// Wait for thread to start before returning
|
||||
wait_cond_.wait(&caller_mutex_);
|
||||
caller_mutex_.unlock();
|
||||
}
|
||||
|
||||
void RendererThread::Cancel()
|
||||
@@ -80,6 +72,11 @@ void RendererThread::run()
|
||||
// Lock mutex for main loop
|
||||
mutex_.lock();
|
||||
|
||||
// Signal that main thread can continue now
|
||||
caller_mutex_.lock();
|
||||
wait_cond_.wakeAll();
|
||||
caller_mutex_.unlock();
|
||||
|
||||
RenderInstance instance(width_, height_, format_, mode_);
|
||||
render_instance_ = &instance;
|
||||
|
||||
@@ -88,17 +85,20 @@ void RendererThread::run()
|
||||
|
||||
// Main loop (use Cancel() to exit it)
|
||||
while (!cancelled_) {
|
||||
// Lock the caller mutex (used in Queue() for thread synchronization)
|
||||
caller_mutex_.lock();
|
||||
|
||||
// Main waiting condition
|
||||
wait_cond_.wait(&mutex_);
|
||||
|
||||
// Unlock the caller mutex
|
||||
// Wake up main thread
|
||||
caller_mutex_.lock();
|
||||
wait_cond_.wakeAll();
|
||||
caller_mutex_.unlock();
|
||||
|
||||
// Process the Node
|
||||
node_->Run(time_);
|
||||
for (int i=path_.size()-1;i>=0;i--) {
|
||||
path_.at(i)->Run(time_);
|
||||
}
|
||||
|
||||
emit FinishedPath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +112,15 @@ void RendererThread::run()
|
||||
|
||||
void RendererThread::StartThread(QThread::Priority priority)
|
||||
{
|
||||
queue_.clear();
|
||||
path_.clear();
|
||||
|
||||
// Start the thread (the thread will unlock caller_mutex_)
|
||||
caller_mutex_.lock();
|
||||
|
||||
// Start the thread
|
||||
QThread::start(priority);
|
||||
|
||||
// Wait for thread to finish completion
|
||||
wait_cond_.wait(&caller_mutex_);
|
||||
|
||||
caller_mutex_.unlock();
|
||||
}
|
||||
|
||||
@@ -28,21 +28,18 @@
|
||||
|
||||
#include "node/node.h"
|
||||
#include "render/renderinstance.h"
|
||||
|
||||
struct RenderQueueEntry {
|
||||
Node* node;
|
||||
rational time;
|
||||
};
|
||||
#include "renderpath.h"
|
||||
|
||||
class RendererThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RendererThread(const int& width,
|
||||
const int& height,
|
||||
const olive::PixelFormat& format,
|
||||
const olive::RenderMode& mode);
|
||||
|
||||
bool Queue(Node* n, const rational &time);
|
||||
void Queue(const RenderThreadPath& path, const rational &time);
|
||||
|
||||
void Cancel();
|
||||
|
||||
@@ -52,6 +49,9 @@ public:
|
||||
|
||||
void StartThread(Priority priority = InheritPriority);
|
||||
|
||||
signals:
|
||||
void FinishedPath();
|
||||
|
||||
private:
|
||||
QWaitCondition wait_cond_;
|
||||
|
||||
@@ -59,7 +59,7 @@ private:
|
||||
|
||||
QMutex caller_mutex_;
|
||||
|
||||
Node* node_;
|
||||
RenderThreadPath path_;
|
||||
|
||||
rational time_;
|
||||
|
||||
@@ -75,8 +75,6 @@ private:
|
||||
|
||||
RenderInstance* render_instance_;
|
||||
|
||||
QVector<RenderQueueEntry> queue_;
|
||||
|
||||
};
|
||||
|
||||
using RendererThreadPtr = std::shared_ptr<RendererThread>;
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#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];
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#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
|
||||
@@ -84,8 +84,8 @@ ShaderPtr ShaderGenerator::DefaultPipeline(const QString& function_name, const Q
|
||||
|
||||
// If additional code was passed, add it and reference it in main().
|
||||
//
|
||||
// The function in the additional code is expected to be `vec4 function_name(vec4 color)`. The texture coordinate can be
|
||||
// acquired through `v_texcoord`.
|
||||
// The function in the additional code is expected to be `vec4 function_name(vec4 color)`. The texture coordinate
|
||||
// can be acquired through `v_texcoord`.
|
||||
|
||||
frag_shader.append(shader_code);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user