diff --git a/app/core.cpp b/app/core.cpp index e7a9fde07..d6a339eaf 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -557,6 +557,7 @@ void Core::DeclareTypesForQt() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); } void Core::StartGUI(bool full_screen) diff --git a/app/node/node.cpp b/app/node/node.cpp index e4927119f..78613fa9b 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -468,6 +468,12 @@ void Node::ProcessSamples(NodeValueDatabase &, const SampleBufferPtr, SampleBuff { } +void Node::GenerateFrame(FramePtr frame, const GenerateJob &job) const +{ + Q_UNUSED(frame) + Q_UNUSED(job) +} + NodeInput *Node::GetInputWithID(const QString &id) const { QList inputs = GetInputsIncludingArrays(); diff --git a/app/node/node.h b/app/node/node.h index addfd631b..91209581a 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -27,6 +27,7 @@ #include #include +#include "codec/frame.h" #include "codec/samplebuffer.h" #include "common/rational.h" #include "common/xmlutils.h" @@ -177,10 +178,19 @@ public: virtual ShaderCode GetShaderCode(const QString& shader_id) const; /** - * @brief If ProcessesSamples() is true, this is the function that will process them. + * @brief If Value() pushes a ShaderJob, this is the function that will process them. */ virtual void ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const; + /** + * @brief If Value() pushes a GenerateJob, override this function for the image to create + * + * @param frame + * + * The destination buffer. It will already be allocated and ready for writing to. + */ + virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const; + /** * @brief Returns the input with the specified ID (or nullptr if it doesn't exist) */ diff --git a/app/node/param.cpp b/app/node/param.cpp index 702702b0a..ff8e72b21 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -214,6 +214,7 @@ QByteArray NodeParam::ValueToBytes(const NodeParam::DataType &type, const QVaria case kVector: case kShaderJob: case kSampleJob: + case kGenerateJob: case kAny: break; } diff --git a/app/node/param.h b/app/node/param.h index 76ae4a796..40e5a9716 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -196,6 +196,15 @@ public: */ kSampleJob = 0x20000, + /** + * Job type + * + * An internal type used to indicate to the renderer that an accelerated sample job needs to + * take place. This value will usually be taken from a table and a kSamples value will be + * pushed to take its place. + */ + kGenerateJob = 0x40000, + /** ****************************** BROAD IDENTIFIERS ****************************** */ diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 7ab230f32..d613060c8 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -140,6 +140,14 @@ QVariant NodeTraverser::ProcessSamples(const Node *node, const TimeRange &range, return QVariant(); } +QVariant NodeTraverser::ProcessFrameGeneration(const Node *node, const GenerateJob &job) +{ + Q_UNUSED(node) + Q_UNUSED(job) + + return QVariant(); +} + QVariant NodeTraverser::GetCachedFrame(const Node *node, const rational &time) { Q_UNUSED(node) @@ -166,8 +174,9 @@ void NodeTraverser::PostProcessTable(const Node *node, const TimeRange &range, N QList audio_footage_to_retrieve; QList shader_jobs_to_run; QList sample_jobs_to_run; + QList generate_jobs_to_run; - for (int i=output_params.Count()-1; i>=0; i--) { + for (int i=0; i* take_this_value_list = nullptr; @@ -186,10 +195,13 @@ void NodeTraverser::PostProcessTable(const Node *node, const TimeRange &range, N take_this_value_list = &shader_jobs_to_run; } else if (v.type() == NodeParam::kSampleJob) { take_this_value_list = &sample_jobs_to_run; + } else if (v.type() == NodeParam::kGenerateJob) { + take_this_value_list = &generate_jobs_to_run; } if (take_this_value_list) { take_this_value_list->append(output_params.TakeAt(i)); + i--; } } @@ -211,6 +223,15 @@ void NodeTraverser::PostProcessTable(const Node *node, const TimeRange &range, N output_params.Push(NodeParam::kTexture, value, node); } } + + // Run generate jobs + foreach (const NodeValue& v, generate_jobs_to_run) { + QVariant value = ProcessFrameGeneration(node, v.data().value()); + + if (!value.isNull()) { + output_params.Push(NodeParam::kTexture, value, node); + } + } } // Retrieve audio samples diff --git a/app/node/traverser.h b/app/node/traverser.h index c7c9651b6..e9e1523fc 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -52,6 +52,8 @@ protected: virtual QVariant ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job); + virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job); + virtual QVariant GetCachedFrame(const Node *node, const rational &time); private: diff --git a/app/render/backend/opengl/openglproxy.cpp b/app/render/backend/opengl/openglproxy.cpp index 9d25d895a..aff4dac42 100644 --- a/app/render/backend/opengl/openglproxy.cpp +++ b/app/render/backend/opengl/openglproxy.cpp @@ -364,6 +364,7 @@ QVariant OpenGLProxy::RunNodeAccelerated(const Node *node, case NodeInput::kVector: case NodeInput::kShaderJob: case NodeInput::kSampleJob: + case NodeInput::kGenerateJob: case NodeInput::kFootage: case NodeInput::kBuffer: case NodeInput::kNone: diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index 6cb628551..7142eae07 100644 --- a/app/render/backend/renderworker.cpp +++ b/app/render/backend/renderworker.cpp @@ -211,6 +211,29 @@ QVariant RenderWorker::ProcessSamples(const Node *node, const TimeRange &range, return QVariant::fromValue(output_buffer); } +QVariant RenderWorker::ProcessFrameGeneration(const Node* node, const GenerateJob &job) +{ + FramePtr frame = Frame::Create(); + + PixelFormat::Format output_fmt; + if (job.GetAlphaChannelRequired()) { + output_fmt = PixelFormat::GetFormatWithAlphaChannel(video_params_.format()); + } else { + output_fmt = PixelFormat::GetFormatWithoutAlphaChannel(video_params_.format()); + } + + frame->set_video_params(VideoParams(video_params_.width(), + video_params_.height(), + video_params_.time_base(), + output_fmt, + video_params_.divider())); + frame->allocate(); + + node->GenerateFrame(frame, job); + + return CachedFrameToTexture(frame); +} + QVariant RenderWorker::GetCachedFrame(const Node* node, const rational& time) { if (node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) { diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h index 665f34b42..a8848c643 100644 --- a/app/render/backend/renderworker.h +++ b/app/render/backend/renderworker.h @@ -126,6 +126,8 @@ protected: virtual QVariant ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; + virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job) override; + virtual QVariant GetCachedFrame(const Node *node, const rational &time) override; virtual bool TextureHasAlpha(const QVariant& v) const = 0; diff --git a/app/render/shaderinfo.h b/app/render/shaderinfo.h index da0c1d2ab..9db03d9e0 100644 --- a/app/render/shaderinfo.h +++ b/app/render/shaderinfo.h @@ -84,13 +84,34 @@ private: }; -class ShaderJob : public AcceleratedJob { +class GenerateJob : public AcceleratedJob { +public: + GenerateJob() + { + alpha_channel_required_ = false; + } + + bool GetAlphaChannelRequired() const + { + return alpha_channel_required_; + } + + void SetAlphaChannelRequired(bool e) + { + alpha_channel_required_ = e; + } + +private: + bool alpha_channel_required_; + +}; + +class ShaderJob : public GenerateJob { public: ShaderJob() { iterations_ = 1; iterative_input_ = nullptr; - alpha_channel_required_ = false; } const QString& GetShaderID() const @@ -119,16 +140,6 @@ public: return iterative_input_; } - bool GetAlphaChannelRequired() const - { - return alpha_channel_required_; - } - - void SetAlphaChannelRequired(bool e) - { - alpha_channel_required_ = e; - } - private: QString id_; @@ -136,8 +147,6 @@ private: NodeInput* iterative_input_; - bool alpha_channel_required_; - }; class ShaderCode { @@ -169,5 +178,6 @@ OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::ShaderJob) Q_DECLARE_METATYPE(OLIVE_NAMESPACE::SampleJob) +Q_DECLARE_METATYPE(OLIVE_NAMESPACE::GenerateJob) #endif // SHADERINFO_H diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 18cd09f16..b59c633a8 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -90,6 +90,7 @@ void NodeParamViewWidgetBridge::CreateWidgets() case NodeParam::kVector: case NodeParam::kShaderJob: case NodeParam::kSampleJob: + case NodeParam::kGenerateJob: break; case NodeParam::kInt: { @@ -266,6 +267,7 @@ void NodeParamViewWidgetBridge::WidgetCallback() case NodeParam::kBuffer: case NodeParam::kShaderJob: case NodeParam::kSampleJob: + case NodeParam::kGenerateJob: break; case NodeParam::kInt: { @@ -398,6 +400,7 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() case NodeParam::kBuffer: case NodeParam::kShaderJob: case NodeParam::kSampleJob: + case NodeParam::kGenerateJob: case NodeParam::kVector: break; case NodeParam::kInt: @@ -453,7 +456,10 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() } case NodeParam::kText: { - static_cast(widgets_.first())->setText(input_->get_value_at_time(node_time).toString()); + QLineEdit* e = static_cast(widgets_.first()); + int pos = e->cursorPosition(); + e->setText(input_->get_value_at_time(node_time).toString()); + e->setCursorPosition(pos); break; } case NodeParam::kBoolean: