diff --git a/app/node/blend/alphaover/alphaover.h b/app/node/blend/alphaover/alphaover.h
index 7289260c5..a0dc65747 100644
--- a/app/node/blend/alphaover/alphaover.h
+++ b/app/node/blend/alphaover/alphaover.h
@@ -34,7 +34,8 @@ public:
virtual QString id() const override;
virtual QString Description() const override;
- virtual QString Code() const override;
+ virtual bool IsAccelerated() const override;
+ virtual QString CodeFragment() const override;
protected:
diff --git a/app/node/block/transition/CMakeLists.txt b/app/node/block/transition/CMakeLists.txt
index 65f672588..60ebb509e 100644
--- a/app/node/block/transition/CMakeLists.txt
+++ b/app/node/block/transition/CMakeLists.txt
@@ -14,6 +14,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+add_subdirectory(crossdissolve)
+add_subdirectory(diptoblack)
+
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/block/transition/transition.h
diff --git a/app/node/color/opacity/opacity.cpp b/app/node/color/opacity/opacity.cpp
index da579b53a..f3df5c33e 100644
--- a/app/node/color/opacity/opacity.cpp
+++ b/app/node/color/opacity/opacity.cpp
@@ -65,7 +65,12 @@ void OpacityNode::Retranslate()
texture_input_->set_name(tr("Texture"));
}
-QString OpacityNode::Code() const
+bool OpacityNode::IsAccelerated() const
+{
+ return true;
+}
+
+QString OpacityNode::CodeFragment() const
{
return "#version 110"
"\n"
diff --git a/app/node/color/opacity/opacity.h b/app/node/color/opacity/opacity.h
index 2eae10ff4..76f7b79fa 100644
--- a/app/node/color/opacity/opacity.h
+++ b/app/node/color/opacity/opacity.h
@@ -39,7 +39,8 @@ public:
virtual void Retranslate() override;
- virtual QString Code() const override;
+ virtual bool IsAccelerated() const override;
+ virtual QString CodeFragment() const override;
NodeInput* texture_input() const;
diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp
index 63c2d4b63..2de06eeab 100644
--- a/app/node/generator/solid/solid.cpp
+++ b/app/node/generator/solid/solid.cpp
@@ -53,7 +53,12 @@ QString SolidGenerator::Description() const
return tr("Generate a solid color.");
}
-QString SolidGenerator::Code() const
+bool SolidGenerator::IsAccelerated() const
+{
+ return true;
+}
+
+QString SolidGenerator::CodeFragment() const
{
return "#version 110\n"
"\n"
diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h
index 1c8cc7106..15b077118 100644
--- a/app/node/generator/solid/solid.h
+++ b/app/node/generator/solid/solid.h
@@ -41,7 +41,8 @@ public:
virtual QString Category() const override;
virtual QString Description() const override;
- virtual QString Code() const override;
+ virtual bool IsAccelerated() const override;
+ virtual QString CodeFragment() const override;
virtual void Retranslate() override;
diff --git a/app/node/graph.cpp b/app/node/graph.cpp
index c2901ec0a..e6f1187ac 100644
--- a/app/node/graph.cpp
+++ b/app/node/graph.cpp
@@ -108,12 +108,3 @@ bool NodeGraph::ContainsNode(Node *n)
{
return (n->parent() == this);
}
-
-void NodeGraph::Release()
-{
- QList all_nodes = nodes();
-
- foreach (Node* n, all_nodes) {
- n->Release();
- }
-}
diff --git a/app/node/graph.h b/app/node/graph.h
index d7a159b94..df3613648 100644
--- a/app/node/graph.h
+++ b/app/node/graph.h
@@ -85,11 +85,6 @@ public:
*/
bool ContainsNode(Node* n);
- /**
- * @brief Releases all Nodes in this NodeGraph
- */
- void Release();
-
signals:
/**
* @brief Signal emitted when a Node is added to the graph
diff --git a/app/node/input/media/video/video.cpp b/app/node/input/media/video/video.cpp
index cbd91dfa4..64a4b7973 100644
--- a/app/node/input/media/video/video.cpp
+++ b/app/node/input/media/video/video.cpp
@@ -1,6 +1,7 @@
#include "video.h"
#include
+#include
#include
#include "core.h"
@@ -40,28 +41,24 @@ QString VideoInput::Description() const
return tr("Import a video footage stream.");
}
-void VideoInput::Release()
-{
- MediaInput::Release();
-}
-
NodeInput *VideoInput::matrix_input() const
{
return matrix_input_;
}
-QString VideoInput::Code() const
+bool VideoInput::IsAccelerated() const
{
- return "#version 110\n"
- "\n"
- "varying vec2 v_texcoord;\n"
- "\n"
- "uniform sampler2D footage_in;\n"
- "uniform mat4 matrix_in;\n"
- "\n"
- "void main(void) {\n"
- " gl_FragColor = texture2D(footage_in, vec2(vec4(v_texcoord, 0.0, 1.0) * matrix_in));\n"
- "}\n";
+ return true;
+}
+
+QString VideoInput::CodeVertex() const
+{
+ return ReadFileAsString(":/shaders/videoinput.vert");
+}
+
+QString VideoInput::CodeFragment() const
+{
+ return ReadFileAsString(":/shaders/videoinput.frag");
}
void VideoInput::Retranslate()
diff --git a/app/node/input/media/video/video.h b/app/node/input/media/video/video.h
index 1f666ae09..6727915d2 100644
--- a/app/node/input/media/video/video.h
+++ b/app/node/input/media/video/video.h
@@ -18,11 +18,11 @@ public:
virtual QString Category() const override;
virtual QString Description() const override;
- virtual void Release() override;
-
NodeInput* matrix_input() const;
- virtual QString Code() const override;
+ virtual bool IsAccelerated() const override;
+ virtual QString CodeVertex() const override;
+ virtual QString CodeFragment() const override;
virtual void Retranslate() override;
diff --git a/app/node/node.cpp b/app/node/node.cpp
index 4f35c6f52..f9b10f784 100644
--- a/app/node/node.cpp
+++ b/app/node/node.cpp
@@ -21,6 +21,7 @@
#include "node.h"
#include
+#include
Node::Node() :
can_be_deleted_(true)
@@ -58,10 +59,6 @@ QString Node::Description() const
return QString();
}
-void Node::Release()
-{
-}
-
void Node::Retranslate()
{
}
@@ -153,6 +150,18 @@ void Node::DependentEdgeChanged(NodeInput *from)
}
}
+QString Node::ReadFileAsString(const QString &filename)
+{
+ QFile f(filename);
+ QString file_data;
+ if (f.open(QFile::ReadOnly | QFile::Text)) {
+ QTextStream text_stream(&f);
+ file_data = text_stream.readAll();
+ f.close();
+ }
+ return file_data;
+}
+
void Node::LockUserInput()
{
user_input_lock_.lock();
@@ -179,11 +188,9 @@ void Node::CopyInputs(Node *source, Node *destination, bool include_connections)
if (p->type() == NodeParam::kInput) {
NodeInput* src = static_cast(p);
- if (src->dependent()) {
- NodeInput* dst = static_cast(dst_param.at(i));
+ NodeInput* dst = static_cast(dst_param.at(i));
- NodeInput::CopyValues(src, dst, include_connections, false);
- }
+ NodeInput::CopyValues(src, dst, include_connections, false);
}
}
@@ -359,7 +366,17 @@ QList Node::GetImmediateDependencies() const
return node_list;
}
-QString Node::Code() const
+bool Node::IsAccelerated() const
+{
+ return false;
+}
+
+QString Node::CodeVertex() const
+{
+ return QString();
+}
+
+QString Node::CodeFragment() const
{
return QString();
}
@@ -442,6 +459,19 @@ NodeOutput *Node::output() const
return output_;
}
+QVariant Node::InputValueFromTable(NodeInput *input, const NodeValueTable &table) const
+{
+ NodeParam::DataType find_data_type = input->data_type();
+
+ // Exception for Footage types (try to get a Texture instead)
+ if (find_data_type == NodeParam::kFootage) {
+ find_data_type = NodeParam::kTexture;
+ }
+
+ // Try to get a value from it
+ return table.Get(find_data_type);
+}
+
void Node::AddInput(NodeInput *input)
{
AddParameter(input);
diff --git a/app/node/node.h b/app/node/node.h
index 3cd1f752f..8a6646130 100644
--- a/app/node/node.h
+++ b/app/node/node.h
@@ -97,11 +97,6 @@ public:
*/
virtual QString Description() const;
- /**
- * @brief Signals the Node that it won't be used for a while and can deallocate some memory
- */
- virtual void Release();
-
/**
* @brief Function called to retranslate parameter names (should be overridden in derivatives)
*/
@@ -136,10 +131,17 @@ public:
*/
QList GetImmediateDependencies() const;
+ virtual bool IsAccelerated() const;
+
/**
- * @brief Generate OpenCL hardware accelerated code for this Node
+ * @brief Generate hardware accelerated code for this Node
*/
- virtual QString Code() const;
+ virtual QString CodeVertex() const;
+
+ /**
+ * @brief Generate hardware accelerated code for this Node
+ */
+ virtual QString CodeFragment() const;
/**
* @brief Returns the parameter with the specified ID (or nullptr if it doesn't exist)
@@ -266,6 +268,8 @@ public:
NodeOutput* output() const;
+ virtual QVariant InputValueFromTable(NodeInput* input, const NodeValueTable& table) const;
+
protected:
void AddInput(NodeInput* input);
@@ -275,6 +279,8 @@ protected:
virtual void DependentEdgeChanged(NodeInput* from);
+ static QString ReadFileAsString(const QString& filename);
+
public slots:
signals:
diff --git a/app/node/output/timeline/tracklist.cpp b/app/node/output/timeline/tracklist.cpp
index 839b9f2d1..79c7968f2 100644
--- a/app/node/output/timeline/tracklist.cpp
+++ b/app/node/output/timeline/tracklist.cpp
@@ -102,16 +102,31 @@ TrackOutput* TrackList::AddTrack()
NodeParam::ConnectEdge(track->output(), assoc_input);
// FIXME: Test code only
- /*if (track_input_->GetSize() > 1) {
- if (current_last_track->output()->IsConnected()) {
- AlphaOverBlend* blend = new AlphaOverBlend();
- GetParentGraph()->AddNode(blend);
+ if (track_input_->GetSize() > 1) {
+ TrackOutput* last_track = nullptr;
- NodeParam::ConnectEdge(track->output(), blend->blend_input());
- NodeParam::ConnectEdge(current_last_track->output(), blend->base_input());
- NodeParam::ConnectEdge(blend->output(), current_last_track->output()->edges().first()->input());
+ for (int i=track_cache_.size()-1;i>=0;i--) {
+ TrackOutput* test_track = track_cache_.at(i);
+
+ if (test_track && test_track != track) {
+ last_track = test_track;
+ break;
+ }
}
- }*/
+
+ if (last_track && last_track->output()->IsConnected()) {
+ foreach (NodeEdgePtr edge, last_track->output()->edges()) {
+ if (edge->input()->parentNode() != track_input_->parentNode()) {
+ AlphaOverBlend* blend = new AlphaOverBlend();
+ GetParentGraph()->AddNode(blend);
+
+ NodeParam::ConnectEdge(track->output(), blend->blend_input());
+ NodeParam::ConnectEdge(last_track->output(), blend->base_input());
+ NodeParam::ConnectEdge(blend->output(), edge->input());
+ }
+ }
+ }
+ }
// End test code
return track;
diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp
index d9f2c8d71..a7872d3a4 100644
--- a/app/project/item/sequence/sequence.cpp
+++ b/app/project/item/sequence/sequence.cpp
@@ -70,6 +70,7 @@ void Sequence::add_default_nodes()
Node* audio_track_output = timeline_output_->track_list(TrackType::kTrackTypeAudio)->AddTrack();
NodeParam::ConnectEdge(video_track_output->output(), viewer_output_->texture_input());
NodeParam::ConnectEdge(audio_track_output->output(), viewer_output_->samples_input());
+ //timeline_output_->track_list(TrackType::kTrackTypeVideo)->AddTrack();
// Update the timebase on these nodes
set_video_params(video_params_);
diff --git a/app/render/backend/audiorenderbackend.cpp b/app/render/backend/audiorenderbackend.cpp
index ba0b0dd07..f2f5d6f8f 100644
--- a/app/render/backend/audiorenderbackend.cpp
+++ b/app/render/backend/audiorenderbackend.cpp
@@ -32,7 +32,7 @@ void AudioRenderBackend::InvalidateCache(const rational &start_range, const rati
RenderBackend::InvalidateCache(start_range, end_range);
rational start_range_adj = qMax(rational(0), start_range);
- rational end_range_adj = qMin(SequenceLength(), end_range);
+ rational end_range_adj = qMin(GetSequenceLength(), end_range);
// Add the range to the list
cache_queue_.append(TimeRange(start_range_adj, end_range_adj));
@@ -41,7 +41,7 @@ void AudioRenderBackend::InvalidateCache(const rational &start_range, const rati
ValidateRanges();
// Queue value update
- QueueValueUpdate(TimeRange(start_range, end_range));
+ QueueValueUpdate();
// Start caching cycle if it hasn't started already
CacheNext();
diff --git a/app/render/backend/audiorenderworker.cpp b/app/render/backend/audiorenderworker.cpp
index 438b62fd7..f1fa9a3b4 100644
--- a/app/render/backend/audiorenderworker.cpp
+++ b/app/render/backend/audiorenderworker.cpp
@@ -28,7 +28,7 @@ FramePtr AudioRenderWorker::RetrieveFromDecoder(DecoderPtr decoder, const TimeRa
return decoder->RetrieveAudio(range.in(), range.out() - range.in(), audio_params_);
}
-NodeValueTable AudioRenderWorker::RenderBlock(TrackOutput *track, const TimeRange &range)
+NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const TimeRange &range)
{
QList active_blocks = track->BlocksAtTimeRange(range);
@@ -42,8 +42,8 @@ NodeValueTable AudioRenderWorker::RenderBlock(TrackOutput *track, const TimeRang
TimeRange range_for_block(qMax(b->in(), range.in()),
qMin(b->out(), range.out()));
- NodeValueTable table = RenderAsSibling(NodeDependency(b,
- range_for_block));
+ NodeValueTable table = ProcessNode(NodeDependency(b,
+ range_for_block));
QByteArray samples_from_this_block = table.Take(NodeParam::kSamples).toByteArray();
int destination_offset = audio_params_.time_to_bytes(range_for_block.in() - range.in());
diff --git a/app/render/backend/audiorenderworker.h b/app/render/backend/audiorenderworker.h
index 4a2fae507..d6f7aaa01 100644
--- a/app/render/backend/audiorenderworker.h
+++ b/app/render/backend/audiorenderworker.h
@@ -18,7 +18,7 @@ protected:
virtual FramePtr RetrieveFromDecoder(DecoderPtr decoder, const TimeRange& range) override;
- virtual NodeValueTable RenderBlock(TrackOutput *track, const TimeRange& range) override;
+ virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range) override;
private:
AudioRenderingParams audio_params_;
diff --git a/app/render/backend/opengl/functions.cpp b/app/render/backend/opengl/functions.cpp
index bd9fcee7a..aa31660c9 100644
--- a/app/render/backend/opengl/functions.cpp
+++ b/app/render/backend/opengl/functions.cpp
@@ -20,7 +20,6 @@
#include "functions.h"
-#include
#include
#include
#include
@@ -64,7 +63,7 @@ const GLfloat flipped_blit_texcoords[] = {
*
* Currently active QOpenGLFunctions object (use context()->functions() if unsure).
*/
-void PrepareToDraw(QOpenGLFunctions* f) {
+void olive::gl::PrepareToDraw(QOpenGLFunctions* f) {
f->glGenerateMipmap(GL_TEXTURE_2D);
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -96,8 +95,8 @@ void olive::gl::Blit(OpenGLShaderPtr pipeline, bool flipped, QMatrix4x4 matrix)
pipeline->bind();
- pipeline->setUniformValue("mvp_matrix", matrix);
- pipeline->setUniformValue("texture", 0);
+ pipeline->setUniformValue("ove_mvpmat", matrix);
+ pipeline->setUniformValue("ove_maintex", 0);
GLuint vertex_location = static_cast(pipeline->attributeLocation("a_position"));
m_vbo.bind();
@@ -135,7 +134,7 @@ void olive::gl::OCIOBlit(OpenGLShaderPtr pipeline,
pipeline->bind();
- pipeline->setUniformValue("tex2", 2);
+ pipeline->setUniformValue("ove_ociolut", 2);
olive::gl::Blit(pipeline, flipped, matrix);
diff --git a/app/render/backend/opengl/functions.h b/app/render/backend/opengl/functions.h
index f64afe376..779dfce78 100644
--- a/app/render/backend/opengl/functions.h
+++ b/app/render/backend/opengl/functions.h
@@ -22,6 +22,7 @@
#define OPENGLFUNCTIONS_H
#include
+#include
#include "openglshader.h"
@@ -47,6 +48,8 @@ void Blit(OpenGLShaderPtr pipeline, bool flipped = false, QMatrix4x4 matrix = QM
void OCIOBlit(OpenGLShaderPtr pipeline, GLuint lut, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
+void PrepareToDraw(QOpenGLFunctions* f);
+
}
}
diff --git a/app/render/backend/opengl/openglbackend.cpp b/app/render/backend/opengl/openglbackend.cpp
index 120c610f5..90491a9fa 100644
--- a/app/render/backend/opengl/openglbackend.cpp
+++ b/app/render/backend/opengl/openglbackend.cpp
@@ -46,8 +46,6 @@ bool OpenGLBackend::InitInternal()
void OpenGLBackend::CloseInternal()
{
- Decompile();
-
master_texture_ = nullptr;
}
@@ -79,16 +77,26 @@ bool OpenGLBackend::CompileInternal()
// Check if we have a shader or not
if (!shader_cache_.Has(n->id())) {
// Since we don't have a shader, compile one now
- QString node_code = n->Code();
// If the node has no code, it mustn't be GPU accelerated
- if (node_code.isEmpty()) {
+ if (!n->IsAccelerated()) {
// We enter a null shader so we don't try to compile this again
shader_cache_.Add(n->id(), nullptr);
} else {
// Since we have shader code, compile it now
OpenGLShaderPtr program;
+ QString frag_code = n->CodeFragment();
+ QString vert_code = n->CodeVertex();
+
+ if (frag_code.isEmpty()) {
+ frag_code = OpenGLShader::CodeDefaultFragment();
+ }
+
+ if (vert_code.isEmpty()) {
+ vert_code = OpenGLShader::CodeDefaultVertex();
+ }
+
if (!(program = std::make_shared())) {
SetError(QStringLiteral("Failed to create OpenGL shader object"));
return false;
@@ -99,12 +107,12 @@ bool OpenGLBackend::CompileInternal()
return false;
}
- if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment, node_code)) {
+ if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code)) {
SetError(QStringLiteral("Failed to add OpenGL fragment shader code"));
return false;
}
- if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex())) {
+ if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code)) {
SetError(QStringLiteral("Failed to add OpenGL vertex shader code"));
return false;
}
@@ -115,8 +123,6 @@ bool OpenGLBackend::CompileInternal()
}
shader_cache_.Add(n->id(), program);
-
- //qDebug() << "Compiled" << connected_output->parent()->id() << "->" << connected_output->id();
}
}
}
diff --git a/app/render/backend/opengl/openglshader.cpp b/app/render/backend/opengl/openglshader.cpp
index 97177b411..13d2d8fd1 100644
--- a/app/render/backend/opengl/openglshader.cpp
+++ b/app/render/backend/opengl/openglshader.cpp
@@ -30,7 +30,6 @@ OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx,
OCIO::ConstProcessorRcPtr processor,
bool alpha_is_associated)
{
-
QOpenGLExtraFunctions* xf = ctx->extraFunctions();
// Create LUT texture
@@ -94,9 +93,9 @@ OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx,
shader_text.append(CodeAlphaReassociate(reassociate_func_name));
// Make OCIO call pass through disassociate and reassociate function
- shader_call = QString("%3(%1(%2(col), tex2));").arg(ocio_func_name,
- disassociate_func_name,
- reassociate_func_name);
+ shader_call = QStringLiteral("%3(%1(%2(col), ove_ociolut));").arg(ocio_func_name,
+ disassociate_func_name,
+ reassociate_func_name);
} else {
@@ -107,18 +106,18 @@ OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx,
shader_text.append(CodeAlphaAssociate(associate_func_name));
// Make OCIO call pass through associate function
- shader_call = QString("%2(%1(col, tex2));").arg(ocio_func_name, associate_func_name);
+ shader_call = QStringLiteral("%2(%1(col, ove_ociolut));").arg(ocio_func_name, associate_func_name);
}
// Add process() function, which GetPipeline() will call if specified
QString process_function_name = "process";
- shader_text.append(QString("\n"
- "uniform sampler3D tex2;\n"
- "\n"
- "vec4 %2(vec4 col) {\n"
- " return %1\n"
- "}\n").arg(shader_call, process_function_name));
+ shader_text.append(QStringLiteral("\n"
+ "uniform sampler3D ove_ociolut;\n"
+ "\n"
+ "vec4 %2(vec4 col) {\n"
+ " return %1\n"
+ "}\n").arg(shader_call, process_function_name));
// Get pipeline-based shader to inject OCIO shader into
@@ -139,10 +138,10 @@ QString OpenGLShader::CodeDefaultFragment(const QString &function_name, const QS
"precision highp float;\n"
"#endif\n"
"\n"
- "uniform sampler2D texture;\n"
+ "uniform sampler2D ove_maintex;\n"
"uniform bool color_only;\n"
"uniform vec4 color_only_color;\n"
- "varying vec2 v_texcoord;\n"
+ "varying vec2 ove_texcoord;\n"
"\n");
// Finish the function with the main function
@@ -157,7 +156,7 @@ QString OpenGLShader::CodeDefaultFragment(const QString &function_name, const QS
" if (color_only) {\n"
" gl_FragColor = color_only_color;"
" } else {\n"
- " vec4 color = texture2D(texture, v_texcoord);\n"
+ " vec4 color = texture2D(ove_maintex, ove_texcoord);\n"
" gl_FragColor = color;\n"
" }\n"
"}\n"));
@@ -167,13 +166,13 @@ QString OpenGLShader::CodeDefaultFragment(const QString &function_name, const QS
// 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`.
+ // can be acquired through `ove_texcoord`.
frag_code.append(shader_code);
frag_code.append(QStringLiteral("\n"
"void main() {\n"
- " vec4 color = %1(texture2D(texture, v_texcoord));\n"
+ " vec4 color = %1(texture2D(ove_maintex, ove_texcoord));\n"
" gl_FragColor = color;\n"
"}\n").arg(function_name));
@@ -192,16 +191,16 @@ QString OpenGLShader::CodeDefaultVertex()
"precision highp float;\n"
"#endif\n"
"\n"
- "uniform mat4 mvp_matrix;\n"
+ "uniform mat4 ove_mvpmat;\n"
"\n"
"attribute vec4 a_position;\n"
"attribute vec2 a_texcoord;\n"
"\n"
- "varying vec2 v_texcoord;\n"
+ "varying vec2 ove_texcoord;\n"
"\n"
"void main() {\n"
- " gl_Position = mvp_matrix * a_position;\n"
- " v_texcoord = a_texcoord;\n"
+ " gl_Position = ove_mvpmat * a_position;\n"
+ " ove_texcoord = a_texcoord;\n"
"}\n");
}
diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp
index 82ff47595..560b76f95 100644
--- a/app/render/backend/opengl/openglworker.cpp
+++ b/app/render/backend/opengl/openglworker.cpp
@@ -141,7 +141,7 @@ void OpenGLWorker::ParametersChangedEvent()
}
}
-void OpenGLWorker::RunNodeAccelerated(Node *node, const NodeValueDatabase *input_params, NodeValueTable *output_params)
+void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable *output_params)
{
OpenGLShaderPtr shader = shader_cache_->Get(node->id());
@@ -174,15 +174,7 @@ void OpenGLWorker::RunNodeAccelerated(Node *node, const NodeValueDatabase *input
// Get value from database at this input
const NodeValueTable& input_data = (*input_params)[input];
- NodeParam::DataType find_data_type = input->data_type();
-
- // Exception for Footage types (try to get a Texture instead)
- if (find_data_type == NodeParam::kFootage) {
- find_data_type = NodeParam::kTexture;
- }
-
- // Try to get a value from it
- QVariant value = input_data.Get(find_data_type);
+ QVariant value = node->InputValueFromTable(input, input_data);
switch (input->data_type()) {
case NodeInput::kInt:
@@ -225,6 +217,16 @@ void OpenGLWorker::RunNodeAccelerated(Node *node, const NodeValueDatabase *input
// Set value to bound texture
shader->setUniformValue(variable_location, input_texture_count);
+ // Set texture resolution if shader wants it
+ int res_param_location = shader->uniformLocation(QStringLiteral("%1_resolution").arg(input->id()));
+ if (res_param_location > -1) {
+ shader->setUniformValue(res_param_location,
+ static_cast(texture->width()),
+ static_cast(texture->height()));
+ }
+
+ olive::gl::PrepareToDraw(functions_);
+
input_texture_count++;
break;
}
@@ -247,9 +249,14 @@ void OpenGLWorker::RunNodeAccelerated(Node *node, const NodeValueDatabase *input
}
}
- // Ensure viewport is correct
+ // Set up OpenGL parameters as necessary
functions_->glViewport(0, 0, video_params().effective_width(), video_params().effective_height());
+ // Provide some standard args
+ shader->setUniformValue("ove_resolution",
+ static_cast(video_params().width()),
+ static_cast(video_params().height()));
+
// Blit this texture through this shader
olive::gl::Blit(shader);
@@ -305,9 +312,8 @@ void OpenGLWorker::FinishInit()
// Store OpenGL functions instance
functions_ = ctx_->functions();
+ functions_->glBlendFunc(GL_ONE, GL_ZERO);
- // Set up OpenGL parameters as necessary
- functions_->glEnable(GL_BLEND);
ParametersChangedEvent();
buffer_.Create(ctx_);
diff --git a/app/render/backend/opengl/openglworker.h b/app/render/backend/opengl/openglworker.h
index f0bba8c76..86bfd936c 100644
--- a/app/render/backend/opengl/openglworker.h
+++ b/app/render/backend/opengl/openglworker.h
@@ -46,7 +46,7 @@ protected:
virtual void FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable* table) override;
- virtual void RunNodeAccelerated(Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params) override;
+ virtual void RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params) override;
virtual void TextureToBuffer(const QVariant& texture, QByteArray& buffer) override;
diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp
index 63e6e4687..d0761f899 100644
--- a/app/render/backend/renderbackend.cpp
+++ b/app/render/backend/renderbackend.cpp
@@ -9,9 +9,9 @@ RenderBackend::RenderBackend(QObject *parent) :
started_(false),
viewer_node_(nullptr),
copied_viewer_node_(nullptr),
- value_update_queued_(false),
recompile_queued_(false),
- input_update_queued_(false)
+ input_update_queued_(false),
+ blocking_(false)
{
}
@@ -51,6 +51,8 @@ void RenderBackend::Close()
started_ = false;
+ Decompile();
+
CloseInternal();
for (int i=0;icopy();
- // Copy values (but not connections yet)
Node::CopyInputs(n, copy, false);
copied_graph_.AddNode(copy);
}
+ // We just copied the inputs, so if an input update is queued, it's unnecessary
+ input_update_queued_ = false;
+
// We know that the first node will be the viewer node since we appended that first in the copy
copied_viewer_node_ = static_cast(copied_graph_.nodes().first());
@@ -183,7 +187,7 @@ void RenderBackend::RegenerateCacheID()
CacheIDChangedEvent(cache_id_);
}
-rational RenderBackend::SequenceLength()
+rational RenderBackend::GetSequenceLength()
{
if (viewer_node_ == nullptr) {
return 0;
@@ -216,16 +220,24 @@ void RenderBackend::CacheNext()
}
if ((input_update_queued_ || recompile_queued_) && !AllProcessorsAreAvailable()) {
- qDebug() << "Blocking render while we wait for all workers to finish...";
+ if (input_update_queued_ && recompile_queued_) {
+ qDebug() << "Input update and recompile queued, blocking while processors are busy...";
+ } else if (input_update_queued_) {
+ qDebug() << "Input update queued, blocking while processors are busy...";
+ } else {
+ qDebug() << "Recompile queued, blocking while processors are busy...";
+ }
+ blocking_ = true;
return;
}
- if (input_update_queued_) {
- UpdateNodeInputs();
- input_update_queued_ = false;
+ if (blocking_) {
+ qDebug() << "Processors are free now";
+ blocking_ = false;
}
if (recompile_queued_) {
+ qDebug() << "Recompile requested, decompiling now...";
Decompile();
recompile_queued_ = false;
}
@@ -235,6 +247,25 @@ void RenderBackend::CacheNext()
return;
}
+ if (input_update_queued_) {
+ qDebug() << "Copied inputs from UI graph";
+
+ for (int i=0;iget_connected_node();
+
+ if (!node_connected_to_viewer) {
+ return;
+ }
+
foreach (RenderWorker* worker, processors_) {
if (cache_queue_.isEmpty()) {
break;
@@ -243,14 +274,16 @@ void RenderBackend::CacheNext()
if (!WorkerIsBusy(worker)) {
TimeRange cache_frame = cache_queue_.takeFirst();
- NodeDependency dep = NodeDependency(GetDependentInput()->get_connected_node(), cache_frame.in(), cache_frame.out());
+ //qDebug() << "Rendering" << cache_frame.in().toDouble() << "-" << cache_frame.out().toDouble();
+
+ NodeDependency dep = NodeDependency(node_connected_to_viewer, cache_frame.in(), cache_frame.out());
+
+ SetWorkerBusyState(worker, true);
QMetaObject::invokeMethod(worker,
"Render",
Qt::QueuedConnection,
Q_ARG(NodeDependency, dep));
-
- SetWorkerBusyState(worker, true);
}
}
}
@@ -270,24 +303,9 @@ const QString &RenderBackend::cache_id() const
return cache_id_;
}
-void RenderBackend::QueueValueUpdate(const TimeRange &range)
+void RenderBackend::QueueValueUpdate()
{
- value_update_queued_ = true;
- value_update_range_ = range;
-}
-
-void RenderBackend::UpdateNodeInputs()
-{
- if (value_update_queued_) {
- for (int i=0;i& threads();
@@ -82,9 +82,7 @@ protected:
const QString& cache_id() const;
- void QueueValueUpdate(const TimeRange& range);
-
- void UpdateNodeInputs();
+ void QueueValueUpdate();
bool WorkerIsBusy(RenderWorker* worker) const;
void SetWorkerBusyState(RenderWorker* worker, bool busy);
@@ -130,14 +128,13 @@ private:
QList source_node_list_;
NodeGraph copied_graph_;
- bool value_update_queued_;
- TimeRange value_update_range_;
-
bool recompile_queued_;
bool input_update_queued_;
QVector processor_busy_state_;
+ bool blocking_;
+
private slots:
void QueueRecompile();
diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp
index 49d02b8cd..5620fd154 100644
--- a/app/render/backend/renderworker.cpp
+++ b/app/render/backend/renderworker.cpp
@@ -37,31 +37,9 @@ void RenderWorker::Render(NodeDependency path)
emit CompletedCache(path, RenderInternal(path));
}
-NodeValueTable RenderWorker::RenderAsSibling(NodeDependency dep)
-{
- Node* node = dep.node();
- QList connected_inputs;
- NodeValueTable value;
-
- //qDebug() << "Processing" << node->id();
-
- // 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->IsTrack()) {
- // If the range is not wholly contained in this Block, we'll need to do some extra processing
- value = RenderBlock(static_cast(node), dep.range());
- } else {
- value = ProcessNodeNormally(NodeDependency(node, dep.range()));
- }
-
- // We're done!
-
- return value;
-}
-
NodeValueTable RenderWorker::RenderInternal(const NodeDependency &path)
{
- return RenderAsSibling(path);
+ return ProcessNode(path);
}
bool RenderWorker::OutputIsAccelerated(Node *output)
@@ -70,7 +48,7 @@ bool RenderWorker::OutputIsAccelerated(Node *output)
return false;
}
-void RenderWorker::RunNodeAccelerated(Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params)
+void RenderWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params)
{
Q_UNUSED(node)
Q_UNUSED(input_params)
@@ -102,9 +80,14 @@ bool RenderWorker::IsStarted()
return started_;
}
-NodeValueTable RenderWorker::ProcessNodeNormally(const NodeDependency& dep)
+NodeValueTable RenderWorker::ProcessNode(const NodeDependency& dep)
{
- Node* node = dep.node();
+ const Node* node = dep.node();
+
+ if (node->IsTrack()) {
+ // If the range is not wholly contained in this Block, we'll need to do some extra processing
+ return RenderBlock(static_cast(node), dep.range());
+ }
// FIXME: Cache certain values here if we've already processed them before
@@ -119,8 +102,8 @@ NodeValueTable RenderWorker::ProcessNodeNormally(const NodeDependency& dep)
if (input->IsConnected()) {
// Value will equal something from the connected node, follow it
- table = ProcessNodeNormally(NodeDependency(input->get_connected_node(),
- input_time));
+ table = ProcessNode(NodeDependency(input->get_connected_node(),
+ 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());
diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h
index 21530c069..e1bcbdba8 100644
--- a/app/render/backend/renderworker.h
+++ b/app/render/backend/renderworker.h
@@ -25,8 +25,6 @@ public slots:
void Render(NodeDependency path);
- NodeValueTable RenderAsSibling(NodeDependency dep);
-
signals:
void CompletedCache(NodeDependency dep, NodeValueTable data);
@@ -39,7 +37,7 @@ protected:
virtual bool OutputIsAccelerated(Node *output);
- virtual void RunNodeAccelerated(Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params);
+ virtual void RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params);
StreamPtr ResolveStreamFromInput(NodeInput* input);
DecoderPtr ResolveDecoderFromInput(StreamPtr stream);
@@ -48,9 +46,9 @@ protected:
virtual void FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable* table) = 0;
- NodeValueTable ProcessNodeNormally(const NodeDependency &dep);
+ NodeValueTable ProcessNode(const NodeDependency &dep);
- virtual NodeValueTable RenderBlock(TrackOutput *track, const TimeRange& range) = 0;
+ virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range) = 0;
private:
bool started_;
diff --git a/app/render/backend/videorenderbackend.cpp b/app/render/backend/videorenderbackend.cpp
index 3e54f4752..5e492894b 100644
--- a/app/render/backend/videorenderbackend.cpp
+++ b/app/render/backend/videorenderbackend.cpp
@@ -47,7 +47,7 @@ void VideoRenderBackend::InvalidateCache(const rational &start_range, const rati
// Adjust range to min/max values
rational start_range_adj = qMax(rational(0), start_range);
- rational end_range_adj = qMin(SequenceLength(), end_range);
+ rational end_range_adj = qMin(GetSequenceLength(), end_range);
qDebug() << "Cache invalidated between"
<< start_range_adj.toDouble()
@@ -99,10 +99,10 @@ void VideoRenderBackend::InvalidateCache(const rational &start_range, const rati
}
// Remove frames after this time code if it's changed
- frame_cache_.Truncate(SequenceLength());
+ frame_cache_.Truncate(GetSequenceLength());
// Queue value update
- QueueValueUpdate(TimeRange(start_range, end_range));
+ QueueValueUpdate();
CacheNext();
}
diff --git a/app/render/backend/videorenderworker.cpp b/app/render/backend/videorenderworker.cpp
index b5a33c2d1..28729aae4 100644
--- a/app/render/backend/videorenderworker.cpp
+++ b/app/render/backend/videorenderworker.cpp
@@ -31,7 +31,7 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path)
emit HashAlreadyExists(path, hash);
} else if (frame_cache_->TryCache(hash)) {
// This hash is available for us to cache, start traversing graph
- value = RenderAsSibling(path);
+ value = ProcessNode(path);
emit CompletedFrame(path, hash, value);
} else {
@@ -47,11 +47,11 @@ FramePtr VideoRenderWorker::RetrieveFromDecoder(DecoderPtr decoder, const TimeRa
return decoder->RetrieveVideo(range.in());
}
-void VideoRenderWorker::HashNodeRecursively(QCryptographicHash *hash, Node* n, const rational& time)
+void VideoRenderWorker::HashNodeRecursively(QCryptographicHash *hash, const Node* n, const rational& time)
{
// Resolve BlockList
if (n->IsTrack()) {
- n = static_cast(n)->BlockAtTime(time);
+ n = static_cast(n)->BlockAtTime(time);
if (!n) {
return;
@@ -66,52 +66,50 @@ void VideoRenderWorker::HashNodeRecursively(QCryptographicHash *hash, Node* n, c
if (param->type() == NodeParam::kInput) {
NodeInput* input = static_cast(param);
- if (input->dependent()) {
- // Get time adjustment
- TimeRange range = n->InputTimeAdjustment(input, TimeRange(time, time));
+ // Get time adjustment
+ TimeRange range = n->InputTimeAdjustment(input, TimeRange(time, time));
- // For a single frame, we only care about one of the times
- rational input_time = range.in();
+ // For a single frame, we only care about one of the times
+ rational input_time = range.in();
- if (input->IsConnected()) {
- // Traverse down this edge
- HashNodeRecursively(hash, input->get_connected_node(), input_time);
- } else {
- // Grab the value at this time
- QVariant value = input->get_value_at_time(input_time);
- hash->addData(NodeParam::ValueToBytes(input->data_type(), value));
- }
+ if (input->IsConnected()) {
+ // Traverse down this edge
+ HashNodeRecursively(hash, input->get_connected_node(), input_time);
+ } else {
+ // Grab the value at this time
+ QVariant value = input->get_value_at_time(input_time);
+ hash->addData(NodeParam::ValueToBytes(input->data_type(), value));
+ }
- // We have one exception for FOOTAGE types, since we resolve the footage into a frame in the renderer
- if (input->data_type() == NodeParam::kFootage) {
- StreamPtr stream = ResolveStreamFromInput(input);
- DecoderPtr decoder = ResolveDecoderFromInput(stream);
+ // We have one exception for FOOTAGE types, since we resolve the footage into a frame in the renderer
+ if (input->data_type() == NodeParam::kFootage) {
+ StreamPtr stream = ResolveStreamFromInput(input);
+ DecoderPtr decoder = ResolveDecoderFromInput(stream);
- if (decoder != nullptr) {
- // Add footage details to hash
+ if (decoder != nullptr) {
+ // Add footage details to hash
- // Footage filename
- hash->addData(stream->footage()->filename().toUtf8());
+ // Footage filename
+ hash->addData(stream->footage()->filename().toUtf8());
- // Footage last modified date
- hash->addData(stream->footage()->timestamp().toString().toUtf8());
+ // Footage last modified date
+ hash->addData(stream->footage()->timestamp().toString().toUtf8());
- // Footage stream
- hash->addData(QString::number(stream->index()).toUtf8());
+ // Footage stream
+ hash->addData(QString::number(stream->index()).toUtf8());
- if (stream->type() == Stream::kImage || stream->type() == Stream::kVideo) {
- ImageStreamPtr video_stream = std::static_pointer_cast(stream);
+ if (stream->type() == Stream::kImage || stream->type() == Stream::kVideo) {
+ ImageStreamPtr video_stream = std::static_pointer_cast(stream);
- // Footage timestamp
- hash->addData(QString::number(decoder->GetTimestampFromTime(time)).toUtf8());
+ // Footage timestamp
+ hash->addData(QString::number(decoder->GetTimestampFromTime(time)).toUtf8());
- // Current colorspace
- // FIXME: Handle empty colorspace...
- hash->addData(video_stream->colorspace().toUtf8());
+ // Current colorspace
+ // FIXME: Handle empty colorspace...
+ hash->addData(video_stream->colorspace().toUtf8());
- // Alpha associated setting
- hash->addData(QString::number(video_stream->premultiplied_alpha()).toUtf8());
- }
+ // Alpha associated setting
+ hash->addData(QString::number(video_stream->premultiplied_alpha()).toUtf8());
}
}
}
@@ -162,7 +160,7 @@ void VideoRenderWorker::Download(NodeDependency dep, QByteArray hash, QVariant t
}
}
-NodeValueTable VideoRenderWorker::RenderBlock(TrackOutput *track, const TimeRange &range)
+NodeValueTable VideoRenderWorker::RenderBlock(const TrackOutput *track, const TimeRange &range)
{
// A frame can only have one active block so we just validate the in point of the range
Block* active_block = track->BlockAtTime(range.in());
@@ -170,8 +168,8 @@ NodeValueTable VideoRenderWorker::RenderBlock(TrackOutput *track, const TimeRang
NodeValueTable table;
if (active_block) {
- table = RenderAsSibling(NodeDependency(active_block,
- range));
+ table = ProcessNode(NodeDependency(active_block,
+ range));
}
return table;
diff --git a/app/render/backend/videorenderworker.h b/app/render/backend/videorenderworker.h
index 20f5d9b0f..bf84f4ced 100644
--- a/app/render/backend/videorenderworker.h
+++ b/app/render/backend/videorenderworker.h
@@ -43,14 +43,12 @@ protected:
virtual FramePtr RetrieveFromDecoder(DecoderPtr decoder, const TimeRange& range) override;
- virtual NodeValueTable RenderBlock(TrackOutput *track, const TimeRange& range) override;
+ virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range) override;
ColorProcessorCache* color_cache();
private:
- void ProcessNode();
-
- void HashNodeRecursively(QCryptographicHash* hash, Node *n, const rational &time);
+ void HashNodeRecursively(QCryptographicHash* hash, const Node *n, const rational &time);
VideoRenderingParams video_params_;
diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp
index f4aad1240..6bdc32f63 100644
--- a/app/widget/nodeview/nodeview.cpp
+++ b/app/widget/nodeview/nodeview.cpp
@@ -49,8 +49,6 @@ void NodeView::SetGraph(NodeGraph *graph)
disconnect(graph_, SIGNAL(NodeRemoved(Node*)), this, SLOT(RemoveNode(Node*)));
disconnect(graph_, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(AddEdge(NodeEdgePtr)));
disconnect(graph_, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(RemoveEdge(NodeEdgePtr)));
-
- graph_->Release();
}
// Clear the scene of all UI objects