diff --git a/app/common/filefunctions.cpp b/app/common/filefunctions.cpp index 23f3abf99..acb9ee8c3 100644 --- a/app/common/filefunctions.cpp +++ b/app/common/filefunctions.cpp @@ -187,4 +187,16 @@ QString FileFunctions::EnsureFilenameExtension(QString fn, const QString &extens return fn; } +QString FileFunctions::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; +} + OLIVE_NAMESPACE_EXIT diff --git a/app/common/filefunctions.h b/app/common/filefunctions.h index 87bcc6375..1251dfad6 100644 --- a/app/common/filefunctions.h +++ b/app/common/filefunctions.h @@ -65,6 +65,8 @@ public: */ static QString EnsureFilenameExtension(QString fn, const QString& extension); + static QString ReadFileAsString(const QString& filename); + }; diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index dad795d02..d8b7f5183 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -69,7 +69,7 @@ NodeValueTable PanNode::Value(NodeValueDatabase &value) const NodeValueTable table = value.Merge(); if (job.HasSamples()) { - float pan_volume = job.GetValue(panning_input_).data().toFloat(); + float pan_volume = job.GetValue(panning_input_).data.toFloat(); if (panning_input_->is_static()) { if (!qIsNull(pan_volume) && job.samples()->audio_params().channel_count() == 2) { if (pan_volume > 0) { diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp index 2dfe7ace4..2073594b2 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp @@ -56,7 +56,7 @@ ShaderCode CrossDissolveTransition::GetShaderCode(const QString &shader_id) cons { Q_UNUSED(shader_id) - return ShaderCode(Node::ReadFileAsString(":/shaders/crossdissolve.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/crossdissolve.frag"), QString()); } void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index 816c75011..eda0b4ef2 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -57,7 +57,7 @@ ShaderCode DipToColorTransition::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(Node::ReadFileAsString(":/shaders/diptoblack.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/diptoblack.frag"), QString()); } void DipToColorTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index 3b339f536..5fc6a863a 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -161,15 +161,15 @@ void TransitionBlock::InsertTransitionTimes(AcceleratedJob *job, const double &t { // Provides total transition progress from 0.0 (start) - 1.0 (end) job->InsertValue(QStringLiteral("ove_tprog_all"), - NodeValue(NodeParam::kFloat, GetTotalProgress(time), this)); + ShaderValue(GetTotalProgress(time), NodeParam::kFloat)); // Provides progress of out section from 1.0 (start) - 0.0 (end) job->InsertValue(QStringLiteral("ove_tprog_out"), - NodeValue(NodeParam::kFloat, GetOutProgress(time), this)); + ShaderValue(GetOutProgress(time), NodeParam::kFloat)); // Provides progress of in section from 0.0 (start) - 1.0 (end) job->InsertValue(QStringLiteral("ove_tprog_in"), - NodeValue(NodeParam::kFloat, GetInProgress(time), this)); + ShaderValue(GetInProgress(time), NodeParam::kFloat)); } void TransitionBlock::BlockConnected(NodeEdgePtr edge) diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 7950f77e9..e9e0005bf 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -83,7 +83,7 @@ void BlurFilterNode::Retranslate() ShaderCode BlurFilterNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/blur.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/blur.frag"), QString()); } NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const @@ -100,19 +100,19 @@ NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const NodeValueTable table = value.Merge(); // If there's no texture, no need to run an operation - if (!job.GetValue(texture_input_).data().isNull()) { + if (!job.GetValue(texture_input_).data.isNull()) { // Check if radius > 0, and both "horiz" and/or "vert" are enabled - if ((job.GetValue(horiz_input_).data().toBool() || job.GetValue(vert_input_).data().toBool()) - && job.GetValue(radius_input_).data().toDouble() > 0.0) { + if ((job.GetValue(horiz_input_).data.toBool() || job.GetValue(vert_input_).data.toBool()) + && job.GetValue(radius_input_).data.toDouble() > 0.0) { // Set iteration count to 2 if we're blurring both horizontally and vertically - if (job.GetValue(horiz_input_).data().toBool() && job.GetValue(vert_input_).data().toBool()) { + if (job.GetValue(horiz_input_).data.toBool() && job.GetValue(vert_input_).data.toBool()) { job.SetIterations(2, texture_input_); } // If we're not repeating pixels, expect an alpha channel to appear - if (!job.GetValue(repeat_edge_pixels_input_).data().toBool()) { + if (!job.GetValue(repeat_edge_pixels_input_).data.toBool()) { job.SetAlphaChannelRequired(true); } @@ -120,7 +120,7 @@ NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const } else { // If we're not performing the blur job, just push the texture - table.Push(job.GetValue(texture_input_)); + table.Push(job.GetValue(texture_input_), this); } } diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index d62c99b37..2cea51f75 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -94,12 +94,12 @@ NodeValueTable StrokeFilterNode::Value(NodeValueDatabase &value) const NodeValueTable table = value.Merge(); - if (!job.GetValue(tex_input_).data().isNull()) { - if (job.GetValue(radius_input_).data().toDouble() > 0.0 - && job.GetValue(opacity_input_).data().toDouble() > 0.0) { + if (!job.GetValue(tex_input_).data.isNull()) { + if (job.GetValue(radius_input_).data.toDouble() > 0.0 + && job.GetValue(opacity_input_).data.toDouble() > 0.0) { table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); } else { - table.Push(job.GetValue(tex_input_)); + table.Push(job.GetValue(tex_input_), this); } } @@ -110,7 +110,7 @@ ShaderCode StrokeFilterNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/stroke.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/stroke.frag"), QString()); } OLIVE_NAMESPACE_EXIT diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 870488cc0..c11324bef 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -89,7 +89,7 @@ ShaderCode PolygonGenerator::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(Node::ReadFileAsString(":/shaders/polygon.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/polygon.frag"), QString()); } NodeValueTable PolygonGenerator::Value(NodeValueDatabase &value) const diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index abcf6491f..0fdafc143 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -77,7 +77,7 @@ ShaderCode SolidGenerator::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/solid.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/solid.frag"), QString()); } OLIVE_NAMESPACE_EXIT diff --git a/app/node/generator/text/text.cpp b/app/node/generator/text/text.cpp index de38f08bd..1ff7c7a95 100644 --- a/app/node/generator/text/text.cpp +++ b/app/node/generator/text/text.cpp @@ -104,7 +104,7 @@ NodeValueTable TextGenerator::Value(NodeValueDatabase &value) const NodeValueTable table = value.Merge(); - if (!job.GetValue(text_input_).data().toString().isEmpty()) { + if (!job.GetValue(text_input_).data.toString().isEmpty()) { table.Push(NodeParam::kGenerateJob, QVariant::fromValue(job), this); } @@ -124,14 +124,14 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const // Set default font QFont default_font; - default_font.setFamily(job.GetValue(font_input_).data().toString()); - default_font.setPointSizeF(job.GetValue(font_size_input_).data().toFloat()); + default_font.setFamily(job.GetValue(font_input_).data.toString()); + default_font.setPointSizeF(job.GetValue(font_size_input_).data.toFloat()); text_doc.setDefaultFont(default_font); // Center by default text_doc.setDefaultTextOption(QTextOption(Qt::AlignCenter)); - text_doc.setHtml(job.GetValue(text_input_).data().toString()); + text_doc.setHtml(job.GetValue(text_input_).data.toString()); // Align to 80% width because that's considered the "title safe" area int tenth_of_width = frame->video_params().width() / 10; @@ -144,7 +144,7 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const // Push 10% inwards to compensate for title safe area p.translate(tenth_of_width, 0); - TextVerticalAlign valign = static_cast(job.GetValue(valign_input_).data().toInt()); + TextVerticalAlign valign = static_cast(job.GetValue(valign_input_).data.toInt()); int doc_height = text_doc.size().height(); switch (valign) { @@ -165,7 +165,7 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const text_doc.drawContents(&p); // Transplant alpha channel to frame - Color rgb = job.GetValue(color_input_).data().value(); + Color rgb = job.GetValue(color_input_).data.value(); for (int x=0; xwidth(); x++) { for (int y=0; yheight(); y++) { uchar src_alpha = img.bits()[img.bytesPerLine() * y + x]; diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index 731a750da..e6b980c66 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -48,7 +48,7 @@ ShaderCode MathNodeBase::GetShaderCodeInternal(const QString &shader_id, NodeInp // No-op frag shader (can we return QString() instead?) operation = QStringLiteral("texture(%1, ove_texcoord)").arg(tex_in->id()); - vert = ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id()); + vert = FileFunctions::ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id()); } else { switch (op) { @@ -329,7 +329,7 @@ NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation o float number = RetrieveNumber(number_val); SampleJob job(val_a.type() == NodeParam::kSamples ? val_a : val_b); - job.InsertValue(number_param, NodeValue(NodeParam::kFloat, number, this)); + job.InsertValue(number_param, ShaderValue(number, NodeParam::kFloat)); if (job.HasSamples()) { if (number_param->is_static()) { diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 092b69455..7c02cc375 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -66,7 +66,7 @@ ShaderCode MergeNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/alphaover.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/alphaover.frag"), QString()); } NodeValueTable MergeNode::Value(NodeValueDatabase &value) const @@ -79,13 +79,13 @@ NodeValueTable MergeNode::Value(NodeValueDatabase &value) const NodeValueTable table = value.Merge(); - if (!job.GetValue(base_in_).data().isNull() || !job.GetValue(blend_in_).data().isNull()) { - if (job.GetValue(base_in_).data().isNull()) { + if (!job.GetValue(base_in_).data.isNull() || !job.GetValue(blend_in_).data.isNull()) { + if (job.GetValue(base_in_).data.isNull()) { // We only have a blend texture, no need to alpha over - table.Push(job.GetValue(blend_in_)); - } else if (job.GetValue(blend_in_).data().isNull()) { + table.Push(job.GetValue(blend_in_), this); + } else if (job.GetValue(blend_in_).data.isNull()) { // We only have a base texture, no need to alpha over - table.Push(job.GetValue(base_in_)); + table.Push(job.GetValue(base_in_), this); } else { // We have both textures, push the job table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); diff --git a/app/node/node.cpp b/app/node/node.cpp index 148c41ee5..c1b90e950 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -270,18 +270,6 @@ QList Node::GetInputsToHash() const return GetInputsIncludingArrays(); } -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 GetInputsIncludingArraysInternal(NodeInputArray* array, QList& list) { foreach (NodeInput* input, array->sub_params()) { diff --git a/app/node/node.h b/app/node/node.h index 5ed6826b7..bcc168c15 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -404,8 +404,6 @@ public: void SetPosition(const QPointF& pos); - static QString ReadFileAsString(const QString& filename); - QList GetInputsIncludingArrays() const; QList GetOutputs() const; diff --git a/app/node/value.cpp b/app/node/value.cpp index ef5ac05bd..fb337253e 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -22,26 +22,6 @@ OLIVE_NAMESPACE_ENTER -NodeValueTable& NodeValueDatabase::operator[](const QString &input_id) -{ - return tables_[input_id]; -} - -NodeValueTable& NodeValueDatabase::operator[](const NodeInput *input) -{ - return tables_[input->id()]; -} - -void NodeValueDatabase::Insert(const QString &key, const NodeValueTable &value) -{ - tables_.insert(key, value); -} - -void NodeValueDatabase::Insert(const NodeInput *key, const NodeValueTable &value) -{ - tables_.insert(key->id(), value); -} - NodeValueTable NodeValueDatabase::Merge() const { QHash copy = tables_; @@ -103,41 +83,6 @@ NodeValue NodeValueTable::TakeWithMeta(const NodeParam::DataType &type, const QS return NodeValue(); } -void NodeValueTable::Push(const NodeValue &value) -{ - values_.append(value); -} - -void NodeValueTable::Push(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag) -{ - Push(NodeValue(type, data, from, tag)); -} - -void NodeValueTable::Prepend(const NodeValue &value) -{ - values_.prepend(value); -} - -void NodeValueTable::Prepend(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag) -{ - Prepend(NodeValue(type, data, from, tag)); -} - -const NodeValue &NodeValueTable::at(int index) const -{ - return values_.at(index); -} - -NodeValue NodeValueTable::TakeAt(int index) -{ - return values_.takeAt(index); -} - -int NodeValueTable::Count() const -{ - return values_.size(); -} - bool NodeValueTable::Has(const NodeParam::DataType &type) const { for (int i=values_.size() - 1;i>=0;i--) { @@ -163,11 +108,6 @@ void NodeValueTable::Remove(const NodeValue &v) } } -bool NodeValueTable::isEmpty() const -{ - return values_.isEmpty(); -} - NodeValueTable NodeValueTable::Merge(QList tables) { diff --git a/app/node/value.h b/app/node/value.h index 448c1c54d..448291d9a 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -24,6 +24,7 @@ #include #include "input.h" +#include "render/shadervalue.h" OLIVE_NAMESPACE_ENTER @@ -72,17 +73,58 @@ public: NodeValue GetWithMeta(const NodeParam::DataType& type, const QString& tag = QString()) const; QVariant Take(const NodeParam::DataType& type, const QString& tag = QString()); NodeValue TakeWithMeta(const NodeParam::DataType& type, const QString& tag = QString()); - void Push(const NodeValue& value); - void Push(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()); - void Prepend(const NodeValue& value); - void Prepend(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()); - const NodeValue& at(int index) const; - NodeValue TakeAt(int index); - int Count() const; + + void Push(const NodeValue& value) + { + values_.append(value); + } + + void Push(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()) + { + Push(NodeValue(type, data, from, tag)); + } + + void Push(const ShaderValue &value, const Node *from) + { + Push(value.type, value.data, from, value.tag); + } + + void Prepend(const NodeValue& value) + { + values_.prepend(value); + } + + void Prepend(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()) + { + Prepend(NodeValue(type, data, from, tag)); + } + + void Prepend(const ShaderValue &value, const Node *from) + { + Prepend(value.type, value.data, from, value.tag); + } + + const NodeValue& at(int index) const + { + return values_.at(index); + } + NodeValue TakeAt(int index) + { + return values_.takeAt(index); + } + + int Count() const + { + return values_.size(); + } + bool Has(const NodeParam::DataType& type) const; void Remove(const NodeValue& v); - bool isEmpty() const; + bool isEmpty() const + { + return values_.isEmpty(); + } static NodeValueTable Merge(QList tables); @@ -98,11 +140,25 @@ class NodeValueDatabase public: NodeValueDatabase() = default; - NodeValueTable& operator[](const QString& input_id); - NodeValueTable& operator[](const NodeInput* input); + NodeValueTable& operator[](const QString& input_id) + { + return tables_[input_id]; + } - void Insert(const QString& key, const NodeValueTable &value); - void Insert(const NodeInput* key, const NodeValueTable& value); + NodeValueTable& operator[](const NodeInput* input) + { + return tables_[input->id()]; + } + + void Insert(const QString& key, const NodeValueTable &value) + { + tables_.insert(key, value); + } + + void Insert(const NodeInput* key, const NodeValueTable& value) + { + tables_.insert(key->id(), value); + } NodeValueTable Merge() const; diff --git a/app/project/item/footage/videostream.cpp b/app/project/item/footage/videostream.cpp index 98cbfd1fc..d96f319c7 100644 --- a/app/project/item/footage/videostream.cpp +++ b/app/project/item/footage/videostream.cpp @@ -159,12 +159,6 @@ void VideoStream::set_colorspace(const QString &color) emit ParametersChanged(); } -QString VideoStream::get_colorspace_match_string() const -{ - return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(), - colorspace()); -} - void VideoStream::ColorConfigChanged() { ColorManager* color_manager = footage()->project()->color_manager(); diff --git a/app/project/item/footage/videostream.h b/app/project/item/footage/videostream.h index 7fe6ba773..aa91707a2 100644 --- a/app/project/item/footage/videostream.h +++ b/app/project/item/footage/videostream.h @@ -90,8 +90,6 @@ public: const QString& colorspace(bool default_if_empty = true) const; void set_colorspace(const QString& color); - QString get_colorspace_match_string() const; - VideoParams::Interlacing interlacing() const { return interlacing_; diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt index c569c0293..6e8f1e43d 100644 --- a/app/render/CMakeLists.txt +++ b/app/render/CMakeLists.txt @@ -30,7 +30,6 @@ set(OLIVE_SOURCES render/colorprocessor.h render/colorprocessorcache.h render/colorprocessor.cpp - render/decodercache.h render/diskmanager.h render/diskmanager.cpp render/framehashcache.h @@ -43,12 +42,14 @@ set(OLIVE_SOURCES render/playbackcache.cpp render/previewautocacher.h render/previewautocacher.cpp + render/rendercache.h render/rendermanager.h render/rendermanager.cpp render/rendermodes.h render/renderprocessor.h render/renderprocessor.cpp render/shaderinfo.h + render/shadervalue.h render/stillimagecache.h render/videoparams.h render/videoparams.cpp diff --git a/app/render/backend/opengl/openglrenderer.cpp b/app/render/backend/opengl/openglrenderer.cpp index 533408e01..117ffdeae 100644 --- a/app/render/backend/opengl/openglrenderer.cpp +++ b/app/render/backend/opengl/openglrenderer.cpp @@ -140,10 +140,6 @@ void OpenGLRenderer::Destroy() // Delete framebuffer functions_->glDeleteFramebuffers(1, &framebuffer_); - // Delete all shaders - qDeleteAll(shader_cache_); - shader_cache_.clear(); - // Delete context if it belongs to us if (context_->parent() == this) { delete context_; @@ -171,8 +167,6 @@ void OpenGLRenderer::AttachTextureAsDestination(Renderer::Texture* texture) GL_TEXTURE_2D, texture->id().value(), 0); - - SetViewport(texture->width(), texture->height()); } void OpenGLRenderer::DetachTextureAsDestination() @@ -221,6 +215,8 @@ QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code) goto error; } + qDebug() << "Shader created successfully"; + return Node::PtrToValue(program); error: @@ -281,51 +277,14 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines functions_->glBindTexture(GL_TEXTURE_2D, current_tex); } -Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob job, VideoParams params) +void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params) { // If this node is iterative, we'll pick up which input here GLuint iterative_input = 0; QList textures_to_bind; bool input_textures_have_alpha = false; - QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID()); - QOpenGLShaderProgram* shader = shader_cache_.value(full_shader_id); - - if (!shader) { - // Since we have shader code, compile it now - ShaderCode code = node->GetShaderCode(job.GetShaderID()); - QString vert_code = code.vert_code(); - QString frag_code = code.frag_code(); - - if (frag_code.isEmpty() && vert_code.isEmpty()) { - qWarning() << "No shader code found for" << node->id() << "- operation will be a no-op"; - } - - if (frag_code.isEmpty()) { - frag_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.frag")); - } - - if (vert_code.isEmpty()) { - vert_code = Node::ReadFileAsString(QStringLiteral(":/shaders/default.vert")); - } - - shader = new QOpenGLShaderProgram(this); - if (shader - && shader->create() - && shader->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code) - && shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code) - && shader->link()) { - shader_cache_.insert(full_shader_id, shader); - } else { - qWarning() << "Failed to compile shader for" << node->id(); - shader = nullptr; - } - - if (!shader) { - // Couldn't find or build the shader required - return nullptr; - } - } + QOpenGLShaderProgram* shader = Node::ValueToPtr(s); shader->bind(); @@ -338,28 +297,25 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j continue; } - // See if this value corresponds to an input (NOTE: it may not and this may be null) - NodeInput* corresponding_input = node->GetInputWithID(it.key()); - // This variable is used in the shader, let's set it - const QVariant& value = it.value().data(); + const ShaderValue& value = it.value(); - NodeParam::DataType data_type = (it.value().type() != NodeParam::kNone) - ? it.value().type() - : corresponding_input->data_type(); + if (value.array) { + qWarning() << "FIXME: Array support is currently a stub"; + } - switch (data_type) { + switch (value.type) { case NodeInput::kInt: // kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to // over/underflows if the number is large enough, but the likelihood of that is quite low. - shader->setUniformValue(variable_location, value.toInt()); + shader->setUniformValue(variable_location, value.data.toInt()); break; case NodeInput::kFloat: // kFloat technically specifies a double but as above, OpenGL doesn't support those. - shader->setUniformValue(variable_location, value.toFloat()); + shader->setUniformValue(variable_location, value.data.toFloat()); break; case NodeInput::kVec2: - if (corresponding_input && corresponding_input->IsArray()) { + /*if (corresponding_input && corresponding_input->IsArray()) { QVector nv = value.value< QVector >(); QVector a(nv.size()); @@ -374,41 +330,42 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j shader->setUniformValue(count_location, a.size()); } } else { - shader->setUniformValue(variable_location, value.value()); - } + + }*/ + shader->setUniformValue(variable_location, value.data.value()); break; case NodeInput::kVec3: - shader->setUniformValue(variable_location, value.value()); + shader->setUniformValue(variable_location, value.data.value()); break; case NodeInput::kVec4: - shader->setUniformValue(variable_location, value.value()); + shader->setUniformValue(variable_location, value.data.value()); break; case NodeInput::kMatrix: - shader->setUniformValue(variable_location, value.value()); + shader->setUniformValue(variable_location, value.data.value()); break; case NodeInput::kCombo: - shader->setUniformValue(variable_location, value.value()); + shader->setUniformValue(variable_location, value.data.value()); break; case NodeInput::kColor: { - Color color = value.value(); + Color color = value.data.value(); shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha()); break; } case NodeInput::kBoolean: - shader->setUniformValue(variable_location, value.toBool()); + shader->setUniformValue(variable_location, value.data.toBool()); break; case NodeInput::kBuffer: case NodeInput::kTexture: { - TexturePtr texture = value.value(); + TexturePtr texture = value.data.value(); // Set value to bound texture shader->setUniformValue(variable_location, textures_to_bind.size()); // If this texture binding is the iterative input, set it here - if (corresponding_input && corresponding_input == job.GetIterativeInput()) { + if (it.key() == job.GetIterativeInput()) { iterative_input = textures_to_bind.size(); } @@ -434,8 +391,8 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j // Adjust virtual width by pixel aspect if necessary if (texture->params().pixel_aspect_ratio() != 1 - || params.pixel_aspect_ratio() != 1) { - double relative_pixel_aspect = texture->params().pixel_aspect_ratio().toDouble() / params.pixel_aspect_ratio().toDouble(); + || destination_params.pixel_aspect_ratio() != 1) { + double relative_pixel_aspect = texture->params().pixel_aspect_ratio().toDouble() / destination_params.pixel_aspect_ratio().toDouble(); adjusted_width = qRound(static_cast(adjusted_width) * relative_pixel_aspect); } @@ -466,32 +423,13 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j } } - // Provide some standard args + // Set ove_resolution to the destination to the "logical" resolution of the destination shader->setUniformValue("ove_resolution", - static_cast(params.width()), - static_cast(params.height())); + static_cast(destination_params.width()), + static_cast(destination_params.height())); - // Create the output textures - int real_iteration_count; - if (job.GetIterationCount() > 1 && job.GetIterativeInput()) { - real_iteration_count = job.GetIterationCount(); - } else { - real_iteration_count = 1; - } - - TexturePtr dst_refs[2]; - dst_refs[0] = CreateTexture(params); - - // If this node requires multiple iterations, get a texture for it too - if (real_iteration_count > 1) { - dst_refs[1] = CreateTexture(params); - } - - // Some nodes use multiple iterations for optimization - TexturePtr input_tex, output_tex; - - // Set up OpenGL parameters as necessary - functions_->glViewport(0, 0, params.effective_width(), params.effective_height()); + // Set the viewport to the "physical" resolution of the destination + functions_->glViewport(0, 0, destination_params.effective_width(), destination_params.effective_height()); // Bind all textures for (int i=0; iglVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr); frag_vbo_.release(); + // Some shaders optimize through multiple iterations which requires ping-ponging textures + // - If there are only two iterations, we can just create one backend texture and then the + // destination can be the second + // - If there are more than two iterations, we need to ping pong back and forth between two + // textures. We can still use the destination as the last iteration, but we'll need textures + // for the iterative process. + int real_iteration_count; + if (job.GetIterationCount() > 1 && !job.GetIterativeInput().isEmpty()) { + real_iteration_count = job.GetIterationCount(); + } else { + real_iteration_count = 1; + } + + TexturePtr output_tex, input_tex; + if (real_iteration_count > 1) { + // Create one texture to bounce off + output_tex = CreateTexture(destination_params); + + if (real_iteration_count > 2) { + // Create a second texture bounce off + input_tex = CreateTexture(destination_params); + } + } + for (int iteration=0; iterationsetUniformValue("ove_iteration", iteration); // Replace iterative input - if (iteration == 0) { - output_tex = dst_refs[0]; + if (iteration == real_iteration_count-1) { + // This is the last iteration, draw to the destination + if (destination) { + // If we have a destination texture, draw to it + AttachTextureAsDestination(destination); + } else if (iteration > 0) { + // Otherwise, if we were iterating before, detach texture now + DetachTextureAsDestination(); + } } else { - input_tex = dst_refs[(iteration+1)%2]; - output_tex = dst_refs[iteration%2]; + // Always draw to output_tex + AttachTextureAsDestination(output_tex.get()); - functions_->glActiveTexture(GL_TEXTURE0 + iterative_input); - functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value()); - PrepareInputTexture(job.GetBilinearFiltering()); + if (iteration > 0) { + // If this is not the first iteration, replace the iterative texture with the one we + // last drew + functions_->glActiveTexture(GL_TEXTURE0 + iterative_input); + functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value()); + PrepareInputTexture(job.GetBilinearFiltering()); + } + + // Swap so that the next iteration, the texture we draw now will be the input texture next + std::swap(output_tex, input_tex); } - AttachTextureAsDestination(output_tex.get()); - // Blit this texture through this shader functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3); } - // Reset framebuffer to default - DetachTextureAsDestination(); + if (destination) { + // Reset framebuffer to default if we were drawing to a texture + DetachTextureAsDestination(); + + // Set metadata for whether this texture has a meaningful alpha channel + destination->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired())); + } // Release any textures we bound before for (int i=textures_to_bind.size()-1; i>=0; i--) { @@ -552,23 +531,9 @@ Renderer::TexturePtr OpenGLRenderer::ProcessShader(const Node *node, ShaderJob j // Release shader shader->release(); - - output_tex->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired())); - - return output_tex; } -void OpenGLRenderer::SetViewport(int width, int height) -{ - functions_->glViewport(0, 0, width, height); -} - -void OpenGLRenderer::BlitColorManaged(ColorProcessorPtr color_processor, Texture *source, Renderer::Texture* destination) -{ - qCritical() << "OpenGLRenderer::BlitColorMangaed is a stub!"; -} - -void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination) +/*void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination) { QOpenGLShaderProgram* program = Node::ValueToPtr(shader); @@ -594,7 +559,7 @@ void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer:: if (destination) { DetachTextureAsDestination(); } -} +}*/ GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format) { diff --git a/app/render/backend/opengl/openglrenderer.h b/app/render/backend/opengl/openglrenderer.h index d0358a680..7634efc4f 100644 --- a/app/render/backend/opengl/openglrenderer.h +++ b/app/render/backend/opengl/openglrenderer.h @@ -51,10 +51,6 @@ public slots: virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override; - virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) override; - - virtual void DetachTextureAsDestination() override; - virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override; virtual void DestroyNativeTexture(QVariant texture) override; @@ -67,21 +63,21 @@ public slots: virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override; - virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node, - OLIVE_NAMESPACE::ShaderJob job, - OLIVE_NAMESPACE::VideoParams params) override; - - virtual void SetViewport(int width, int height) override; - - virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) override; - - virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) override; +protected slots: + virtual void Blit(QVariant shader, + OLIVE_NAMESPACE::ShaderJob job, + OLIVE_NAMESPACE::Renderer::Texture* destination, + OLIVE_NAMESPACE::VideoParams destination_params) override; private: static GLint GetInternalFormat(PixelFormat::Format format); static GLenum GetPixelType(PixelFormat::Format format); + void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture); + + void DetachTextureAsDestination(); + void PrepareInputTexture(bool bilinear); QOpenGLContext* context_; @@ -98,8 +94,6 @@ private: GLuint framebuffer_; - QHash shader_cache_; - }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/renderer.cpp b/app/render/backend/renderer.cpp index a1ddaa924..33897c7b1 100644 --- a/app/render/backend/renderer.cpp +++ b/app/render/backend/renderer.cpp @@ -20,6 +20,13 @@ #include "renderer.h" +#include +namespace OCIO = OCIO_NAMESPACE::v1; + +#include + +#include "render/colormanager.h" + OLIVE_NAMESPACE_ENTER Renderer::Renderer(QObject *parent) : @@ -39,4 +46,91 @@ Renderer::TexturePtr Renderer::CreateTexture(const VideoParams ¶m, void *dat return std::make_shared(this, v, param); } +// copied from source code to OCIODisplay +/*const int OCIO_LUT3D_EDGE_SIZE = 64; + +const int OCIO_LUT3D_PIXEL_COUNT = OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE; +const int OCIO_LUT3D_ENTRY_COUNT = 3 * OCIO_LUT3D_PIXEL_COUNT; +const int OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA = 4 * OCIO_LUT3D_PIXEL_COUNT; +const int OCIO_LUT2D_EDGE_SIZE = 512;*/ + +void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture *destination) +{ + /*ColorContext color_ctx; + + if (color_cache_.contains(color_processor->id())) { + color_ctx = color_cache_.value(color_processor->id()); + } else { + // Generate OCIO color context + + // Generate OCIO shader descriptor + const char* ocio_func_name = "OCIODisplay"; + OCIO::GpuShaderDesc shader_desc; + shader_desc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); + shader_desc.setFunctionName(ocio_func_name); + shader_desc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE); + + // Generate LUT + QVector lut_data(OCIO_LUT3D_ENTRY_COUNT); + color_processor->GetProcessor()->getGpuLut3D(lut_data.data(), shader_desc); + + // Convert to half float RGBA + QVector texture_ready_lut_data(OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA); + for (int i=0; iGetProcessor()->getGpuShaderText(shader_desc); + ocio_code.replace(QStringLiteral("texture3D"), QStringLiteral("texture2D")); + ocio_code.replace(QStringLiteral("sampler3D"), QStringLiteral("sampler2D")); + + + + qDebug() << frag_code; + + //qDebug() << "FIXME: GPU doesn't handle associated alpha yet"; + }*/ + + qDebug() << "BlitColorManaged is a partial stub"; + + QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert"))); + + ShaderJob job; + job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture)); + + BlitToTexture(shader, job, destination); +} + +void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params) +{ + qDebug() << "BlitColorManaged is a partial stub"; + + QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert"))); + + ShaderJob job; + job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture)); + + Blit(shader, job, params); +} + OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/renderer.h b/app/render/backend/renderer.h index 0d8088af8..382228244 100644 --- a/app/render/backend/renderer.h +++ b/app/render/backend/renderer.h @@ -121,12 +121,22 @@ public: TexturePtr CreateTexture(const VideoParams& param, void* data = nullptr, int linesize = 0); - struct ShaderValue { - QVariant data; - NodeParam::DataType type; - }; + void BlitToTexture(QVariant shader, + OLIVE_NAMESPACE::ShaderJob job, + OLIVE_NAMESPACE::Renderer::Texture* destination) + { + Blit(shader, job, destination, destination->params()); + } - using ShaderUniformMap = QHash; + void Blit(QVariant shader, + OLIVE_NAMESPACE::ShaderJob job, + OLIVE_NAMESPACE::VideoParams params) + { + Blit(shader, job, nullptr, params); + } + + void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture* destination); + void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params); public slots: virtual void PostInit() = 0; @@ -135,10 +145,6 @@ public slots: virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0; - virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) = 0; - - virtual void DetachTextureAsDestination() = 0; - virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) = 0; virtual void DestroyNativeTexture(QVariant texture) = 0; @@ -151,18 +157,19 @@ public slots: virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) = 0; - virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node, - OLIVE_NAMESPACE::ShaderJob job, - OLIVE_NAMESPACE::VideoParams params) = 0; - - virtual void SetViewport(int width, int height) = 0; - - virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) = 0; - - virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) = 0; +protected slots: + virtual void Blit(QVariant shader, + OLIVE_NAMESPACE::ShaderJob job, + OLIVE_NAMESPACE::Renderer::Texture* destination, + OLIVE_NAMESPACE::VideoParams destination_params) = 0; private: + struct ColorContext { + QVariant shader; + TexturePtr lut; + }; + QHash color_cache_; }; diff --git a/app/render/backend/rendererthreadwrapper.cpp b/app/render/backend/rendererthreadwrapper.cpp index eed470ec7..8b024054e 100644 --- a/app/render/backend/rendererthreadwrapper.cpp +++ b/app/render/backend/rendererthreadwrapper.cpp @@ -76,17 +76,6 @@ void RendererThreadWrapper::ClearDestination(double r, double g, double b, doubl Q_ARG(double, a)); } -void RendererThreadWrapper::AttachTextureAsDestination(Renderer::Texture *texture) -{ - QMetaObject::invokeMethod(inner_, "AttachTextureAsDestination", Qt::BlockingQueuedConnection, - OLIVE_NS_ARG(Renderer::Texture*, texture)); -} - -void RendererThreadWrapper::DetachTextureAsDestination() -{ - QMetaObject::invokeMethod(inner_, "DetachTextureAsDestination", Qt::BlockingQueuedConnection); -} - QVariant RendererThreadWrapper::CreateNativeTexture(VideoParams param, void *data, int linesize) { QVariant v; @@ -139,41 +128,15 @@ void RendererThreadWrapper::DownloadFromTexture(Renderer::Texture *texture, void Q_ARG(int, linesize)); } -Renderer::TexturePtr RendererThreadWrapper::ProcessShader(const Node *node, ShaderJob job, VideoParams params) +void RendererThreadWrapper::Blit(QVariant shader, ShaderJob job, Renderer::Texture *destination, VideoParams destination_params) { Renderer::TexturePtr tex; QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection, - OLIVE_NS_RETURN_ARG(Renderer::TexturePtr, tex), - OLIVE_NS_CONST_ARG(Node*, node), - OLIVE_NS_ARG(ShaderJob, job), - OLIVE_NS_ARG(VideoParams, params)); - - return tex; -} - -void RendererThreadWrapper::SetViewport(int width, int height) -{ - QMetaObject::invokeMethod(inner_, "SetViewport", Qt::BlockingQueuedConnection, - Q_ARG(int, width), - Q_ARG(int, height)); -} - -void RendererThreadWrapper::BlitColorManaged(ColorProcessorPtr color_processor, Renderer::Texture *source, Renderer::Texture *destination) -{ - QMetaObject::invokeMethod(inner_, "BlitColorManaged", Qt::BlockingQueuedConnection, - OLIVE_NS_ARG(ColorProcessorPtr, color_processor), - OLIVE_NS_ARG(Renderer::Texture*, source), - OLIVE_NS_ARG(Renderer::Texture*, destination)); -} - -void RendererThreadWrapper::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination) -{ - QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection, - OLIVE_NS_ARG(Renderer::Texture*, source), Q_ARG(QVariant, shader), - Q_ARG(Renderer::ShaderUniformMap, parameters), - OLIVE_NS_ARG(Renderer::Texture*, destination)); + OLIVE_NS_ARG(ShaderJob, job), + OLIVE_NS_ARG(Renderer::Texture*, destination), + OLIVE_NS_ARG(VideoParams, destination_params)); } OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/rendererthreadwrapper.h b/app/render/backend/rendererthreadwrapper.h index d8bd05bb0..95445bc25 100644 --- a/app/render/backend/rendererthreadwrapper.h +++ b/app/render/backend/rendererthreadwrapper.h @@ -47,10 +47,6 @@ public slots: virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override; - virtual void AttachTextureAsDestination(OLIVE_NAMESPACE::Renderer::Texture* texture) override; - - virtual void DetachTextureAsDestination() override; - virtual QVariant CreateNativeTexture(OLIVE_NAMESPACE::VideoParams param, void* data = nullptr, int linesize = 0) override; virtual void DestroyNativeTexture(QVariant texture) override; @@ -63,15 +59,11 @@ public slots: virtual void DownloadFromTexture(OLIVE_NAMESPACE::Renderer::Texture* texture, void* data, int linesize) override; - virtual TexturePtr ProcessShader(const OLIVE_NAMESPACE::Node* node, - OLIVE_NAMESPACE::ShaderJob job, - OLIVE_NAMESPACE::VideoParams params) override; - - virtual void SetViewport(int width, int height) override; - - virtual void BlitColorManaged(OLIVE_NAMESPACE::ColorProcessorPtr color_processor, OLIVE_NAMESPACE::Renderer::Texture* source, OLIVE_NAMESPACE::Renderer::Texture *destination = nullptr) override; - - virtual void Blit(OLIVE_NAMESPACE::Renderer::Texture* source, QVariant shader, OLIVE_NAMESPACE::Renderer::ShaderUniformMap parameters, OLIVE_NAMESPACE::Renderer::Texture* destination = nullptr) override; +protected slots: + virtual void Blit(QVariant shader, + OLIVE_NAMESPACE::ShaderJob job, + OLIVE_NAMESPACE::Renderer::Texture* destination, + OLIVE_NAMESPACE::VideoParams destination_params) override; private: Renderer* inner_; diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index cee97fb43..e33942fd2 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -54,6 +54,8 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const output.toUtf8()); } + + id_ = GenerateID(config, input, transform); } void ColorProcessor::ConvertFrame(Frame *f) @@ -75,6 +77,15 @@ Color ColorProcessor::ConvertColor(Color in) return in; } +QString ColorProcessor::GenerateID(ColorManager *config, const QString &input, const ColorTransform &transform) +{ + return QStringLiteral("%1:%2:%3:%4:%5").arg(config->GetConfigFilename(), + input, + transform.display(), + transform.view(), + transform.look()); +} + ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform) { return std::make_shared(config, input, transform); diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h index 6912cd66d..f2c2e6a2e 100644 --- a/app/render/colorprocessor.h +++ b/app/render/colorprocessor.h @@ -53,9 +53,18 @@ public: Color ConvertColor(Color in); + const QString& id() const + { + return id_; + } + + static QString GenerateID(ColorManager* config, const QString& input, const ColorTransform& dest_space); + private: OCIO::ConstProcessorRcPtr processor_; + QString id_; + }; using ColorProcessorChain = QList; diff --git a/app/render/colortransform.h b/app/render/colortransform.h index cd183dda3..45e605c8d 100644 --- a/app/render/colortransform.h +++ b/app/render/colortransform.h @@ -22,7 +22,6 @@ #define COLORTRANSFORM_H #include -namespace OCIO = OCIO_NAMESPACE::v1; #include diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index e8e4d72eb..cbf09a06f 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -19,7 +19,8 @@ PreviewAutoCacher::PreviewAutoCacher() : last_update_time_(0), ignore_next_mouse_button_(false), video_params_changed_(false), - audio_params_changed_(false) + audio_params_changed_(false), + color_manager_(nullptr) { // Set default autocache range SetPlayhead(rational()); @@ -582,7 +583,7 @@ void PreviewAutoCacher::TryRender() single_frame_render_->Start(); watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_, - static_cast(viewer_node_->parent())->project()->color_manager(), + color_manager_, single_frame_render_->property("time").value(), RenderMode::kOffline, true)); @@ -624,7 +625,7 @@ void PreviewAutoCacher::RequeueFrames() connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::VideoRendered); video_tasks_.insert(watcher, hash); watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_, - static_cast(viewer_node_->parent())->project()->color_manager(), + color_manager_, t, RenderMode::kOffline, false)); } } diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h index c6b993b5d..663ee7bc2 100644 --- a/app/render/previewautocacher.h +++ b/app/render/previewautocacher.h @@ -6,6 +6,7 @@ #include "config/config.h" #include "node/node.h" #include "node/output/viewer/viewer.h" +#include "render/colormanager.h" #include "threading/threadticketwatcher.h" OLIVE_NAMESPACE_ENTER @@ -83,6 +84,11 @@ public: void ClearAudioQueue(bool wait = false); void ClearVideoDownloadQueue(bool wait = false); + void SetColorManager(ColorManager* manager) + { + color_manager_ = manager; + } + public slots: /** * @brief Main handler for when the NodeGraph changes @@ -148,6 +154,8 @@ private: bool audio_params_changed_; + ColorManager* color_manager_; + private slots: /** * @brief Handler for when the NodeGraph reports a video change over a certain time range diff --git a/app/render/decodercache.h b/app/render/rendercache.h similarity index 78% rename from app/render/decodercache.h rename to app/render/rendercache.h index e43023274..2c9745083 100644 --- a/app/render/decodercache.h +++ b/app/render/rendercache.h @@ -18,15 +18,16 @@ ***/ -#ifndef DECODERCACHE_H -#define DECODERCACHE_H +#ifndef RENDERCACHE_H +#define RENDERCACHE_H #include "codec/decoder.h" #include "project/item/footage/stream.h" OLIVE_NAMESPACE_ENTER -class DecoderCache : public QHash +template +class RenderCache : public QHash { public: QMutex *mutex() @@ -39,6 +40,9 @@ private: }; +using DecoderCache = RenderCache; +using ShaderCache = RenderCache; + OLIVE_NAMESPACE_EXIT -#endif // DECODERCACHE_H +#endif // RENDERCACHE_H diff --git a/app/render/rendermanager.cpp b/app/render/rendermanager.cpp index cacf1ed90..9ad31cd65 100644 --- a/app/render/rendermanager.cpp +++ b/app/render/rendermanager.cpp @@ -55,6 +55,7 @@ RenderManager::RenderManager(QObject *parent) : still_cache_ = new StillImageCache(); decoder_cache_ = new DecoderCache(); + shader_cache_ = new ShaderCache(); } else { qCritical() << "Tried to initialize unknown graphics backend"; still_cache_ = nullptr; @@ -64,6 +65,7 @@ RenderManager::RenderManager(QObject *parent) : RenderManager::~RenderManager() { + delete shader_cache_; delete decoder_cache_; delete still_cache_; @@ -162,7 +164,7 @@ RenderTicketPtr RenderManager::SaveFrameToCache(FrameHashCache *cache, FramePtr void RenderManager::RunTicket(RenderTicketPtr ticket) const { - RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_); + RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_, shader_cache_); } OLIVE_NAMESPACE_EXIT diff --git a/app/render/rendermanager.h b/app/render/rendermanager.h index b04935b40..5277c83bd 100644 --- a/app/render/rendermanager.h +++ b/app/render/rendermanager.h @@ -26,11 +26,11 @@ #include "config/config.h" #include "colorprocessorcache.h" #include "dialog/rendercancel/rendercancel.h" -#include "decodercache.h" #include "node/graph.h" #include "node/output/viewer/viewer.h" #include "node/traverser.h" #include "render/backend/renderer.h" +#include "rendercache.h" #include "stillimagecache.h" #include "threading/threadpool.h" @@ -127,6 +127,8 @@ private: DecoderCache* decoder_cache_; + ShaderCache* shader_cache_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 1f4c61837..e18712446 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -29,11 +29,12 @@ OLIVE_NAMESPACE_ENTER -RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache) : +RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache *shader_cache) : ticket_(ticket), render_ctx_(render_ctx), still_image_cache_(still_image_cache), - decoder_cache_(decoder_cache) + decoder_cache_(decoder_cache), + shader_cache_(shader_cache) { } @@ -137,9 +138,9 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(StreamPtr stream) return decoder; } -void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache) +void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache, ShaderCache *shader_cache) { - RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache); + RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache, shader_cache); p.Run(); } @@ -228,9 +229,10 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational & // to optimize such a situation VideoStreamPtr video_stream = std::static_pointer_cast(stream); const VideoParams& video_params = Node::ValueToPtr(ticket_->property("viewer"))->video_params(); + StillImageCache::Entry want_entry = {nullptr, stream, - video_stream->get_colorspace_match_string(), + ColorProcessor::GenerateID(Node::ValueToPtr(ticket_->property("colormanager")), video_stream->colorspace(), ColorTransform(OCIO::ROLE_SCENE_LINEAR)), video_stream->premultiplied_alpha(), video_params.divider(), (video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time}; @@ -293,14 +295,14 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational & managed_params.set_format(video_params.format()); value = render_ctx_->CreateTexture(managed_params); - // FIXME: Accessing video_stream->colorspace() + qDebug() << "FIXME: Accessing video_stream->colorspace() may cause race conditions"; ColorManager* color_manager = video_stream->footage()->project()->color_manager(); ColorProcessorPtr processor = ColorProcessor::Create(color_manager, video_stream->colorspace(), ColorTransform(OCIO::ROLE_SCENE_LINEAR)); - render_ctx_->BlitColorManaged(processor, unmanaged_texture.get(), value.get()); + render_ctx_->BlitColorManaged(processor, unmanaged_texture, value.get()); still_image_cache_->mutex()->lock(); @@ -341,9 +343,30 @@ QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range { Q_UNUSED(range) + QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID()); + + QMutexLocker locker(shader_cache_->mutex()); + + QVariant shader = shader_cache_->value(full_shader_id); + + if (shader.isNull()) { + // Since we have shader code, compile it now + shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID())); + + if (shader.isNull()) { + // Couldn't find or build the shader required + return QVariant(); + } + } + const VideoParams& video_params = Node::ValueToPtr(ticket_->property("viewer"))->video_params(); - return QVariant::fromValue(render_ctx_->ProcessShader(node, job, video_params)); + Renderer::TexturePtr destination = render_ctx_->CreateTexture(video_params); + + // Run shader + render_ctx_->BlitToTexture(shader, job, destination.get()); + + return QVariant::fromValue(destination); } QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) @@ -372,7 +395,7 @@ QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &rang if (corresponding_input) { value = ProcessInput(corresponding_input, TimeRange(this_sample_time, this_sample_time)); } else { - value.Push(j.value()); + value.Push(j.value(), node); } value_db.Insert(j.key(), value); diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 2b85315bd..e2be6eb61 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -21,9 +21,9 @@ #ifndef RENDERPROCESSOR_H #define RENDERPROCESSOR_H -#include "decodercache.h" #include "node/traverser.h" #include "render/backend/renderer.h" +#include "rendercache.h" #include "stillimagecache.h" #include "threading/threadticket.h" @@ -32,7 +32,7 @@ OLIVE_NAMESPACE_ENTER class RenderProcessor : public NodeTraverser { public: - static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache); + static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache); struct RenderedWaveform { const TrackOutput* track; @@ -56,7 +56,7 @@ protected: virtual QVariant GetCachedFrame(const Node *node, const rational &time) override; private: - RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache); + RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache); void Run(); @@ -70,6 +70,8 @@ private: DecoderCache* decoder_cache_; + ShaderCache* shader_cache_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/shaderinfo.h b/app/render/shaderinfo.h index 8af331d9a..680b32bef 100644 --- a/app/render/shaderinfo.h +++ b/app/render/shaderinfo.h @@ -2,56 +2,73 @@ #define SHADERINFO_H #include "codec/samplebuffer.h" +#include "common/filefunctions.h" #include "node/input.h" #include "node/inputarray.h" #include "node/value.h" OLIVE_NAMESPACE_ENTER -using NodeValueMap = QHash; +using NodeValueMap = QHash; class AcceleratedJob { public: AcceleratedJob() = default; - NodeValue GetValue(NodeInput* input) const + ShaderValue GetValue(NodeInput* input) const { return value_map_.value(input->id()); } - NodeValue GetValue(const QString& input) const + ShaderValue GetValue(const QString& input) const { return value_map_.value(input); } void InsertValue(NodeInput* input, NodeValueDatabase& value) { + ShaderValue shader_val; + + shader_val.type = input->data_type(); + shader_val.array = input->IsArray(); + if (input->IsArray()) { NodeInputArray* array = static_cast(input); - QVector values(array->GetSize()); + QVector values(array->GetSize()); for (int j=0;jGetSize();j++) { NodeInput* subparam = array->At(j); - values[j] = value[subparam].TakeWithMeta(subparam->data_type()); + values[j] = value[subparam].Take(subparam->data_type()); } - InsertValue(input->id(), NodeValue(NodeParam::kVec2, QVariant::fromValue(values), input->parentNode())); + shader_val.data = QVariant::fromValue(values); } else { - InsertValue(input->id(), value[input].TakeWithMeta(input->data_type())); + NodeValue node_val = value[input].TakeWithMeta(input->data_type()); + shader_val.data = node_val.data(); + shader_val.tag = node_val.tag(); } + + InsertValue(input->id(), shader_val); } - void InsertValue(const QString& input, const NodeValue& value) + void InsertValue(const QString& input, const ShaderValue& value) { value_map_.insert(input, value); } - void InsertValue(NodeInput* input, const NodeValue& value) + void InsertValue(NodeInput* input, const ShaderValue& value) { value_map_.insert(input->id(), value); } + void InsertValue(NodeInput* input, const NodeValue& value) + { + ShaderValue s(value.data(), value.type()); + s.tag = value.tag(); + value_map_.insert(input->id(), s); + } + const NodeValueMap &GetValues() const { return value_map_; @@ -127,15 +144,20 @@ public: const QString& GetShaderID() const { - return id_; + return shader_id_; } void SetShaderID(const QString& id) { - id_ = id; + shader_id_ = id; } void SetIterations(int iterations, NodeInput* iterative_input) + { + SetIterations(iterations, iterative_input->id()); + } + + void SetIterations(int iterations, const QString& iterative_input) { iterations_ = iterations; iterative_input_ = iterative_input; @@ -146,7 +168,7 @@ public: return iterations_; } - NodeInput* GetIterativeInput() const + const QString& GetIterativeInput() const { return iterative_input_; } @@ -162,11 +184,11 @@ public: } private: - QString id_; + QString shader_id_; int iterations_; - NodeInput* iterative_input_; + QString iterative_input_; bool bilinear_; @@ -178,6 +200,13 @@ public: frag_code_(frag_code), vert_code_(vert_code) { + if (frag_code_.isEmpty()) { + frag_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.frag")); + } + + if (vert_code_.isEmpty()) { + vert_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert")); + } } const QString& frag_code() const diff --git a/app/render/shadervalue.h b/app/render/shadervalue.h new file mode 100644 index 000000000..5d4e8dbfb --- /dev/null +++ b/app/render/shadervalue.h @@ -0,0 +1,53 @@ +/*** + + 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 . + +***/ + +#ifndef SHADERVALUE_H +#define SHADERVALUE_H + +#include "node/param.h" + +OLIVE_NAMESPACE_ENTER + +struct ShaderValue +{ + ShaderValue() + { + type = NodeParam::kNone; + array = false; + } + + ShaderValue(QVariant data_in, NodeParam::DataType type_in, bool array_in = false) + { + data = data_in; + type = type_in; + array = array_in; + } + + NodeParam::DataType type; + QVariant data; + bool array; + + QString tag; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // SHADERVALUE_H diff --git a/app/shaders/default.frag b/app/shaders/default.frag index 62a34b668..181773f5c 100644 --- a/app/shaders/default.frag +++ b/app/shaders/default.frag @@ -15,7 +15,6 @@ in vec2 ove_texcoord; out vec4 fragColor; void main() { - vec2 using_texcoord = ove_texcoord; vec4 color = texture(ove_maintex, ove_texcoord); fragColor = color; -} \ No newline at end of file +} diff --git a/app/widget/manageddisplay/manageddisplay.cpp b/app/widget/manageddisplay/manageddisplay.cpp index 27b4b3a9d..cd0636b6d 100644 --- a/app/widget/manageddisplay/manageddisplay.cpp +++ b/app/widget/manageddisplay/manageddisplay.cpp @@ -248,6 +248,13 @@ void ManagedDisplayWidget::doneCurrent() } } +void ManagedDisplayWidget::update() +{ + if (RenderManager::instance()->backend() == RenderManager::kOpenGL) { + static_cast(inner_widget_)->update(); + } +} + Menu* ManagedDisplayWidget::GetDisplayMenu(QMenu* parent, bool auto_connect) { QStringList displays = color_manager()->ListAvailableDisplays(); diff --git a/app/widget/manageddisplay/manageddisplay.h b/app/widget/manageddisplay/manageddisplay.h index ae73dc30e..26c122df7 100644 --- a/app/widget/manageddisplay/manageddisplay.h +++ b/app/widget/manageddisplay/manageddisplay.h @@ -114,6 +114,11 @@ public: */ Menu* GetLookMenu(QMenu* parent, bool auto_connect = true); + /** + * @brief Passes update signal through to inner widget + */ + void update(); + public slots: /** * @brief Replaces the color transform with a new one diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index 44f6a95e8..04255a275 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -43,8 +43,8 @@ void HistogramScope::OnInit() { ScopeBase::OnInit(); - ShaderCode secondary_code(Node::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag"), - Node::ReadFileAsString(":/shaders/rgbhistogram.vert")); + ShaderCode secondary_code(FileFunctions::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag"), + FileFunctions::ReadFileAsString(":/shaders/rgbhistogram.vert")); pipeline_secondary_ = renderer()->CreateNativeShader(secondary_code); } @@ -58,8 +58,8 @@ void HistogramScope::OnDestroy() ShaderCode HistogramScope::GenerateShaderCode() { - return ShaderCode(Node::ReadFileAsString(":/shaders/rgbhistogram.frag"), - Node::ReadFileAsString(":/shaders/default.vert")); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/rgbhistogram.frag"), + FileFunctions::ReadFileAsString(":/shaders/default.vert")); } void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline) @@ -71,11 +71,11 @@ void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeli float histogram_base = 2.5f; float histogram_power = 1.0f / histogram_base; - Renderer::ShaderUniformMap value_map; + ShaderJob shader_job; - value_map.insert(QStringLiteral("viewport"), {QVector2D(width(), height()), NodeParam::kVec2}); - value_map.insert(QStringLiteral("histogram_scale"), {histogram_scale, NodeParam::kFloat}); - value_map.insert(QStringLiteral("histogram_power"), {histogram_power, NodeParam::kFloat}); + shader_job.InsertValue(QStringLiteral("viewport"), ShaderValue(QVector2D(width(), height()), NodeParam::kVec2)); + shader_job.InsertValue(QStringLiteral("histogram_scale"), ShaderValue(histogram_scale, NodeParam::kFloat)); + shader_job.InsertValue(QStringLiteral("histogram_power"), ShaderValue(histogram_power, NodeParam::kFloat)); if (!texture_row_sums_ || texture_row_sums_->width() != this->width() @@ -83,9 +83,13 @@ void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeli texture_row_sums_ = renderer()->CreateTexture(VideoParams(width(), height(), managed_tex->format())); } - renderer()->Blit(managed_tex.get(), pipeline, value_map, texture_row_sums_.get()); + // Draw managed texture to a sums texture + shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); + renderer()->BlitToTexture(pipeline, shader_job, texture_row_sums_.get()); - renderer()->Blit(texture_row_sums_.get(), pipeline_secondary_, value_map); + // Draw sums into a histogram + shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture_row_sums_), NodeParam::kTexture)); + renderer()->Blit(pipeline_secondary_, shader_job, texture_row_sums_->params()); // Draw line overlays QPainter p(this); diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index 60aff3da6..89644e589 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -50,7 +50,11 @@ void ScopeBase::showEvent(QShowEvent* e) void ScopeBase::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline) { - renderer()->Blit(managed_tex.get(), pipeline, Renderer::ShaderUniformMap()); + ShaderJob job; + + job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); + + renderer()->Blit(pipeline, job, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F)); } void ScopeBase::UploadTextureFromBuffer() @@ -98,9 +102,8 @@ void ScopeBase::OnPaint() if (buffer_) { // Convert reference frame to display space - renderer()->BlitColorManaged(color_service(), texture_.get(), managed_tex_.get()); + renderer()->BlitColorManaged(color_service(), texture_, managed_tex_.get()); - renderer()->SetViewport(width(), height()); DrawScope(managed_tex_, pipeline_); } } diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index f1da05fce..618ed64b8 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -44,8 +44,8 @@ WaveformScope::~WaveformScope() ShaderCode WaveformScope::GenerateShaderCode() { - return ShaderCode(Node::ReadFileAsString(":/shaders/rgbwaveform.frag"), - Node::ReadFileAsString(":/shaders/rgbwaveform.vert")); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/rgbwaveform.frag"), + FileFunctions::ReadFileAsString(":/shaders/rgbwaveform.vert")); } void WaveformScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeline) @@ -53,23 +53,28 @@ void WaveformScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipelin float waveform_scale = 0.80f; // Draw waveform through shader - Renderer::ShaderUniformMap value_map; + ShaderJob job; // Set viewport size - value_map.insert(QStringLiteral("viewport"), - {QVector2D(width(), height()), NodeParam::kVec2}); + job.InsertValue(QStringLiteral("viewport"), + ShaderValue(QVector2D(width(), height()), NodeParam::kVec2)); // Set luma coefficients float luma_coeffs[3] = {0.0f, 0.0f, 0.0f}; color_manager()->GetDefaultLumaCoefs(luma_coeffs); - value_map.insert(QStringLiteral("luma_coeffs"), - {QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3}); + job.InsertValue(QStringLiteral("luma_coeffs"), + ShaderValue(QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3)); // Scale of the waveform relative to the viewport surface. - value_map.insert(QStringLiteral("waveform_scale"), {waveform_scale, NodeParam::kFloat}); + job.InsertValue(QStringLiteral("waveform_scale"), + ShaderValue(waveform_scale, NodeParam::kFloat)); - renderer()->Blit(managed_tex.get(), pipeline, value_map); + // Insert source texture + job.InsertValue(QStringLiteral("ove_maintex"), + ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); + + renderer()->Blit(pipeline, job, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F)); float waveform_dim_x = ceil((width() - 1.0) * waveform_scale); float waveform_dim_y = ceil((height() - 1.0) * waveform_scale); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index b46619cbc..8e47ee9c9 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -202,6 +202,8 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n) using_manager = nullptr; } + auto_cacher_.SetColorManager(using_manager); + display_widget_->ConnectColorManager(using_manager); foreach (ViewerWindow* window, windows_) { window->display_widget()->ConnectColorManager(using_manager); @@ -244,6 +246,7 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n) foreach (ViewerWindow* window, windows_) { window->display_widget()->DisconnectColorManager(); } + auto_cacher_.SetColorManager(nullptr); waveform_view_->SetViewer(nullptr); waveform_view_->ConnectTimelinePoints(nullptr); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index f0dec4726..b4fb272f7 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -297,9 +297,8 @@ void ViewerDisplayWidget::OnPaint() //color_service()->pipeline()->setUniformValue("ove_deinterlace", deinterlace_); } - // Bind retrieved texture - renderer()->SetViewport(width(), height()); - renderer()->BlitColorManaged(color_service(), texture_.get()); + // Draw texture through color transform + renderer()->BlitColorManaged(color_service(), texture_, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F)); }