diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index b57781fbc..bf344f3ac 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -65,11 +65,16 @@ void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) GenerateProcessor(); } +ShaderCode ChromaKeyNode::GetShaderCode(const QString &) const +{ + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/chromakey.frag"))); +} + void ChromaKeyNode::GenerateProcessor() { if (manager()){ ColorTransform transform("cie_xyz_d65_interchange"); - set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); + set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); } } @@ -78,12 +83,13 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, if (!value[kTextureInput].data().isNull() && processor()) { ColorTransformJob job; + job.InsertValue(value); job.SetColorProcessor(processor()); job.SetInputTexture(value[kTextureInput].data().value()); - job.SetShaderPath(QStringLiteral(":/shaders/chromakey.frag")); + job.SetNeedsCustomShader(this); table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); } } -} // namespace olive \ No newline at end of file +} // namespace olive diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index c14272e02..870601551 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -37,6 +37,7 @@ class ChromaKeyNode : public OCIOBaseNode { virtual void InputValueChangedEvent(const QString& input, int element) override; + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; virtual void ConfigChanged() override {}; diff --git a/app/render/alphaassoc.h b/app/render/alphaassoc.h new file mode 100644 index 000000000..22eb74835 --- /dev/null +++ b/app/render/alphaassoc.h @@ -0,0 +1,34 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 ALPHAASSOC_H +#define ALPHAASSOC_H + +namespace olive { + +enum AlphaAssociated { + kAlphaNone, + kAlphaUnassociated, + kAlphaAssociated +}; + +} + +#endif // ALPHAASSOC_H diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index 3bed475f8..dc7f7331e 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -21,19 +21,28 @@ #ifndef COLORTRANSFORMJOB_H #define COLORTRANSFORMJOB_H +#include #include +#include "render/job/acceleratedjob.h" +#include "render/alphaassoc.h" #include "render/colorprocessor.h" #include "render/texture.h" namespace olive { -class ColorTransformJob { +class Node; + +class ColorTransformJob : public AcceleratedJob +{ public: ColorTransformJob() { processor_ = nullptr; input_texture_ = nullptr; + custom_shader_src_ = nullptr; + input_alpha_association_ = kAlphaNone; + clear_destination_ = true; } TexturePtr GetInputTexture() const { return input_texture_; } @@ -42,15 +51,41 @@ public: ColorProcessorPtr GetColorProcessor() const { return processor_; } void SetColorProcessor(ColorProcessorPtr p) { processor_ = p; } - QString GetShaderPath() const { return shader_path_; } - void SetShaderPath(const QString shader_path) { shader_path_ = shader_path; } + const AlphaAssociated &GetInputAlphaAssociation() const { return input_alpha_association_; } + void SetInputAlphaAssociation(const AlphaAssociated &e) { input_alpha_association_ = e; } + + const Node *CustomShaderSource() const { return custom_shader_src_; } + const QString &CustomShaderID() const { return custom_shader_id_; } + void SetNeedsCustomShader(const Node *node, const QString &id = QString()) + { + custom_shader_src_ = node; + custom_shader_id_ = id; + } + + bool IsClearDestinationEnabled() const { return clear_destination_; } + void SetClearDestinationEnabled(bool e) { clear_destination_ = e; } + + const QMatrix4x4 &GetTransformMatrix() const { return matrix_; } + void SetTransformMatrix(const QMatrix4x4 &m) { matrix_ = m; } + + const QMatrix4x4 &GetCropMatrix() const { return crop_matrix_; } + void SetCropMatrix(const QMatrix4x4 &m) { crop_matrix_ = m; } private: ColorProcessorPtr processor_; TexturePtr input_texture_; - QString shader_path_; + const Node *custom_shader_src_; + QString custom_shader_id_; + + AlphaAssociated input_alpha_association_; + + bool clear_destination_; + + QMatrix4x4 matrix_; + + QMatrix4x4 crop_matrix_; }; diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 3eb7070e5..a4c0ae989 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -52,21 +52,6 @@ TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data, return CreateTexture(params, Texture::k2D, data, linesize); } -void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture *destination, bool clear_destination, const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix) -{ - BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix); -} - -void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) -{ - BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix, shader_path); -} - -void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) -{ - BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix); -} - TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms) { color_cache_mutex_.lock(); @@ -108,14 +93,16 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const Vide return std::make_shared(this, v, params, type); } -bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx, QString shader_path) +bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::ColorContext *ctx) { QMutexLocker locker(&color_cache_mutex_); ColorContext& color_ctx = *ctx; - if (color_cache_.contains(color_processor->id())) { - color_ctx = color_cache_.value(color_processor->id()); + QString proc_id = color_job.GetColorProcessor()->id(); + + if (color_cache_.contains(proc_id)) { + color_ctx = color_cache_.value(proc_id); return true; } else { // Create shader description @@ -126,22 +113,21 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo shader_desc->setResourcePrefix("ocio_"); // Generate shader - color_processor->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc); + color_job.GetColorProcessor()->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc); - QString shader_frag; - if (shader_path.isEmpty()) { - // Generate shader code using OCIO stub and our auto-generated name - shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")) - .arg(shader_desc->getShaderText(), ocio_func_name); + ShaderCode code; + if (const Node *shader_src = color_job.CustomShaderSource()) { + // Use shader code from associated node + code = shader_src->GetShaderCode(color_job.CustomShaderID()); } else { - // FIXME: Currently only supports a single function - shader_frag = FileFunctions::ReadFileAsString(shader_path) - .arg(shader_desc->getShaderText(), ocio_func_name); + // Generate shader code using OCIO stub and our auto-generated name + code = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")); } + code.set_frag_code(code.frag_code().arg(shader_desc->getShaderText(), ocio_func_name)); + // Try to compile shader - color_ctx.compiled_shader = CreateNativeShader(ShaderCode(shader_frag, - FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert")))); + color_ctx.compiled_shader = CreateNativeShader(code); if (color_ctx.compiled_shader.isNull()) { return false; @@ -209,32 +195,25 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; } - color_cache_.insert(color_processor->id(), color_ctx); + color_cache_.insert(proc_id, color_ctx); return true; } } -void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, - AlphaAssociated source_alpha_association, Texture *destination, - VideoParams params, bool clear_destination, const QMatrix4x4& matrix, - const QMatrix4x4& crop_matrix, const QString shader_path) +void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *destination, const VideoParams ¶ms) { ColorContext color_ctx; - if (!GetColorContext(color_processor, &color_ctx, shader_path)) { + if (!GetColorContext(color_job, &color_ctx)) { return; } ShaderJob job; - if (shader_path.isEmpty()) { - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source))); - } else { - // If we are using a custom shader in a node use "tex_in" for consistency - job.InsertValue(QStringLiteral("tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source))); - } - job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix)); - job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix.inverted())); - job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, source_alpha_association)); + job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(color_job.GetInputTexture()))); + job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix())); + job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, color_job.GetCropMatrix().inverted())); + job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, color_job.GetInputAlphaAssociation())); + job.InsertValue(color_job.GetValues()); foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { job.InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); @@ -246,9 +225,9 @@ void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, Textu } if (destination) { - BlitToTexture(color_ctx.compiled_shader, job, destination, clear_destination); + BlitToTexture(color_ctx.compiled_shader, job, destination, color_job.IsClearDestinationEnabled()); } else { - Blit(color_ctx.compiled_shader, job, params, clear_destination); + Blit(color_ctx.compiled_shader, job, params, color_job.IsClearDestinationEnabled()); } } diff --git a/app/render/renderer.h b/app/render/renderer.h index 58e306c4b..e46ec7990 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -29,6 +29,7 @@ #include "common/timerange.h" #include "node/node.h" #include "render/colorprocessor.h" +#include "render/job/colortransformjob.h" #include "render/videoparams.h" #include "texture.h" @@ -63,15 +64,15 @@ public: Blit(shader, job, nullptr, params, clear_destination); } - enum AlphaAssociated { - kAlphaNone, - kAlphaUnassociated, - kAlphaAssociated - }; - - void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); - void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); - void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); + void BlitColorManaged(const ColorTransformJob &color_job, Texture* destination, const VideoParams ¶ms); + void BlitColorManaged(const ColorTransformJob &job, Texture* destination) + { + BlitColorManaged(job, destination, destination->params()); + } + void BlitColorManaged(const ColorTransformJob &job, const VideoParams ¶ms) + { + BlitColorManaged(job, nullptr, params); + } TexturePtr InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms); @@ -127,12 +128,7 @@ private: }; - bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx, const QString shader_path); - - void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, - AlphaAssociated source_alpha_association, - Texture* destination, VideoParams params, bool clear_destination, - const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix, const QString shader_path = QString()); + bool GetColorContext(const ColorTransformJob &color_job, ColorContext* ctx); QHash color_cache_; diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 55963a965..5098ec8d9 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -99,9 +99,14 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time if (output_color_transform) { // Yes color transform, blit color managed - render_ctx_->BlitColorManaged(output_color_transform, texture, - Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, - blit_tex.get(), true, matrix); + ColorTransformJob job; + + job.SetColorProcessor(output_color_transform); + job.SetInputTexture(texture); + job.SetInputAlphaAssociation(Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? kAlphaAssociated : kAlphaNone); + job.SetTransformMatrix(matrix); + + render_ctx_->BlitColorManaged(job, blit_tex.get()); } else { // No color transform, just blit ShaderJob job; @@ -452,19 +457,21 @@ TexturePtr RenderProcessor::ProcessVideoFootage(const FootageJob &stream, const using_colorspace, color_manager->GetReferenceColorSpace()); - Renderer::AlphaAssociated alpha_assoc; + ColorTransformJob job; + + job.SetColorProcessor(processor); + job.SetInputTexture(unmanaged_texture); + if (stream_data.channel_count() != VideoParams::kRGBAChannelCount || stream_data.colorspace() == color_manager->GetReferenceColorSpace()) { - alpha_assoc = Renderer::kAlphaNone; + job.SetInputAlphaAssociation(kAlphaNone); } else if (stream_data.premultiplied_alpha()) { - alpha_assoc = Renderer::kAlphaAssociated; + job.SetInputAlphaAssociation(kAlphaAssociated); } else { - alpha_assoc = Renderer::kAlphaUnassociated; + job.SetInputAlphaAssociation(kAlphaUnassociated); } - render_ctx_->BlitColorManaged(processor, unmanaged_texture, - alpha_assoc, - value.get()); + render_ctx_->BlitColorManaged(job, value.get()); return value; } @@ -571,7 +578,7 @@ TexturePtr RenderProcessor::ProcessColorTransform(const Node *node, const ColorT TexturePtr src = job.GetInputTexture(); TexturePtr dest = render_ctx_->CreateTexture(src->params()); - render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get(), job.GetShaderPath()); + render_ctx_->BlitColorManaged(job, dest.get()); return dest; } @@ -600,7 +607,13 @@ TexturePtr RenderProcessor::ProcessFrameGeneration(const Node *node, const Gener TexturePtr dest = render_ctx_->CreateTexture(GetCacheVideoParams()); ColorManager* color_manager = Node::ValueToPtr(ticket_->property("colormanager")); ColorProcessorPtr cp = ColorProcessor::Create(color_manager, job.GetColorspace(), color_manager->GetReferenceColorSpace()); - render_ctx_->BlitColorManaged(cp, texture, Renderer::kAlphaAssociated, dest.get()); + ColorTransformJob ctj; + + ctj.SetColorProcessor(cp); + ctj.SetInputTexture(texture); + ctj.SetInputAlphaAssociation(kAlphaAssociated); + + render_ctx_->BlitColorManaged(ctj, dest.get()); texture = dest; } diff --git a/app/render/shadercode.h b/app/render/shadercode.h index c41422122..20c8b8079 100644 --- a/app/render/shadercode.h +++ b/app/render/shadercode.h @@ -33,15 +33,11 @@ public: { } - const QString& frag_code() const - { - return frag_code_; - } + const QString& frag_code() const { return frag_code_; } + void set_frag_code(const QString &f) { frag_code_ = f; } - const QString& vert_code() const - { - return vert_code_; - } + const QString& vert_code() const { return vert_code_; } + void set_vert_code(const QString &v) { vert_code_ = v; } private: QString frag_code_; diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index 8e6074e74..2e152e052 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -74,7 +74,13 @@ void ScopeBase::OnPaint() if (!managed_tex_ || !managed_tex_up_to_date_ || managed_tex_->params() != texture_->params()) { managed_tex_ = renderer()->CreateTexture(texture_->params()); - renderer()->BlitColorManaged(color_service(), texture_, Renderer::kAlphaNone, managed_tex_.get()); + + ColorTransformJob job; + job.SetColorProcessor(color_service()); + job.SetInputTexture(texture_); + job.SetInputAlphaAssociation(kAlphaNone); + + renderer()->BlitColorManaged(job, managed_tex_.get()); } DrawScope(managed_tex_, pipeline_); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 7914763a9..a74d65d75 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -485,10 +485,15 @@ void ViewerDisplayWidget::OnPaint() texture_to_draw = deinterlace_texture_; } - renderer()->BlitColorManaged(color_service(), texture_to_draw, - Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, - device_params, false, - combined_matrix_flipped_, crop_matrix_); + ColorTransformJob ctj; + ctj.SetColorProcessor(color_service()); + ctj.SetInputTexture(texture_to_draw); + ctj.SetInputAlphaAssociation(Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? kAlphaAssociated : kAlphaNone); + ctj.SetClearDestinationEnabled(false); + ctj.SetTransformMatrix(combined_matrix_flipped_); + ctj.SetCropMatrix(crop_matrix_); + + renderer()->BlitColorManaged(ctj, device_params); } }