diff --git a/app/common/ocioutils.cpp b/app/common/ocioutils.cpp index 950632c3e..cc8a0490a 100644 --- a/app/common/ocioutils.cpp +++ b/app/common/ocioutils.cpp @@ -44,7 +44,7 @@ OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(VideoParams::Format for return OCIO::BIT_DEPTH_UNKNOWN; } -OCIO::GradingRGBM OCIOUtils::QVec4ToRGBM(QVector4D vector) +OCIO::GradingRGBM OCIOUtils::QVec4ToRGBM(const QVector4D &vector) { OCIO::GradingRGBM rgbm; diff --git a/app/common/ocioutils.h b/app/common/ocioutils.h index 511d7730b..545231b10 100644 --- a/app/common/ocioutils.h +++ b/app/common/ocioutils.h @@ -35,7 +35,7 @@ class OCIOUtils public: static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format); - static OCIO::GradingRGBM QVec4ToRGBM(QVector4D vector); + static OCIO::GradingRGBM QVec4ToRGBM(const QVector4D &vector); }; } diff --git a/app/node/color/CMakeLists.txt b/app/node/color/CMakeLists.txt index 6f616da89..0cdea800e 100644 --- a/app/node/color/CMakeLists.txt +++ b/app/node/color/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(colormanager) add_subdirectory(displaytransform) +add_subdirectory(ociobase) add_subdirectory(ociogradingtransform) set(OLIVE_SOURCES diff --git a/app/node/color/colormanager/colormanager.cpp b/app/node/color/colormanager/colormanager.cpp index 4f946a513..3a4bea28e 100644 --- a/app/node/color/colormanager/colormanager.cpp +++ b/app/node/color/colormanager/colormanager.cpp @@ -269,6 +269,7 @@ void ColorManager::InputValueChangedEvent(const QString &input, int element) try { SetConfig(OCIO::Config::CreateFromFile(GetConfigFilename().toUtf8())); + emit ConfigChanged(); } catch (OCIO::Exception&) {} } diff --git a/app/node/color/colormanager/colormanager.h b/app/node/color/colormanager/colormanager.h index 2dccc7270..26ea7cc90 100644 --- a/app/node/color/colormanager/colormanager.h +++ b/app/node/color/colormanager/colormanager.h @@ -124,6 +124,9 @@ public: virtual void Retranslate() override; +signals: + void ConfigChanged(); + protected: virtual void InputValueChangedEvent(const QString &input, int element) override; diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp index 19f8d4dc1..7e0bcdcd8 100644 --- a/app/node/color/displaytransform/displaytransform.cpp +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -1,70 +1,42 @@ /*** + 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 . + ***/ #include "displaytransform.h" -#include "node/project/project.h" -#include "render/colorprocessor.h" +#include "node/color/colormanager/colormanager.h" namespace olive { -const QString DisplayTransformNode::kTextureInput = QStringLiteral("tex_in"); const QString DisplayTransformNode::kDisplayInput = QStringLiteral("display_in"); const QString DisplayTransformNode::kViewInput = QStringLiteral("view_in"); const QString DisplayTransformNode::kDirectionInput = QStringLiteral("dir_in"); +#define super OCIOBaseNode + DisplayTransformNode::DisplayTransformNode() { - AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + AddInput(kDisplayInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kDisplayInput, NodeValue::kCombo, 0); + AddInput(kViewInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kViewInput, NodeValue::kCombo, 0); - - AddInput(kDirectionInput, NodeValue::kCombo, 0); - - Retranslate(); -} - -void DisplayTransformNode::GenerateProcessor() -{ - if (!project()) { - return; - } - if (view_.isEmpty()) { - Retranslate(); - } - - ColorTransform transform(display_, view_, ""); - - reference_to_display_ = ColorProcessor::Create(project()->color_manager(), - project()->color_manager()->GetReferenceColorSpace(), transform); - - // Create shader description - shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); - shader_desc_->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); - shader_desc_->setFunctionName("DisplayTransform"); - shader_desc_->setResourcePrefix("ocio_"); - - // Generate shader - reference_to_display_->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc_); -} - -Node *DisplayTransformNode::copy() const -{ - return new DisplayTransformNode(); + AddInput(kDirectionInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); } QString DisplayTransformNode::Name() const @@ -74,7 +46,7 @@ QString DisplayTransformNode::Name() const QString DisplayTransformNode::id() const { - return QStringLiteral("org.olivevideoeditor.Olive.disaplaytransform"); + return QStringLiteral("org.olivevideoeditor.Olive.displaytransform"); } QVector DisplayTransformNode::Category() const @@ -89,66 +61,83 @@ QString DisplayTransformNode::Description() const void DisplayTransformNode::Retranslate() { + super::Retranslate(); + SetInputName(kTextureInput, tr("Input")); SetInputName(kDisplayInput, tr("Display")); SetInputName(kViewInput, tr("View")); - - if (project()) { - SetComboBoxStrings(kDisplayInput, project()->color_manager()->ListAvailableDisplays()); - display_ = project()->color_manager()->ListAvailableDisplays().at( - GetSplitStandardValue(kDisplayInput).at(0).toString().toInt()); - - SetComboBoxStrings(kViewInput, project()->color_manager()->ListAvailableViews(display_)); - view_ = project()->color_manager()->ListAvailableViews(display_).at( - GetSplitStandardValue(kViewInput).at(0).toString().toInt()); - } - SetInputName(kDirectionInput, tr("Direction")); SetComboBoxStrings(kDirectionInput, {tr("Forward"), tr("Inverse")}); } -void DisplayTransformNode::InputValueChangedEvent(const QString &input, int element) { +void DisplayTransformNode::InputValueChangedEvent(const QString &input, int element) +{ Q_UNUSED(element); - if (input == kDirectionInput) { + if (input == kDisplayInput || input == kDirectionInput || input == kViewInput) { + if (input == kDisplayInput) { + UpdateViews(); + } GenerateProcessor(); } - if (project()) { - if (input == kDisplayInput) { - display_ = project()->color_manager()->ListAvailableDisplays().at( - GetSplitStandardValue(kDisplayInput).at(0).toString().toInt()); - // If we change the display the view menu must be updated - Retranslate(); - GenerateProcessor(); - } - if (input == kViewInput) { - view_ = project()->color_manager()->ListAvailableViews(display_).at( - GetSplitStandardValue(kViewInput).at(0).toString().toInt()); - GenerateProcessor(); +} + +QString DisplayTransformNode::GetDisplay() const +{ + if (manager()) { + int index = GetStandardValue(kDisplayInput).toInt(); + if (index < manager()->ListAvailableDisplays().size()) { + return manager()->ListAvailableDisplays().at(index); } } - + return QString(); } -ShaderCode DisplayTransformNode::GetShaderCode(const QString &shader_id) const +QString DisplayTransformNode::GetView() const { - Q_UNUSED(shader_id) - // Generate shader code using OCIO stub and our auto-generated name - QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/displaytransform.frag")) - .arg(shader_desc_->getShaderText()); - return ShaderCode(shader_frag); + if (manager()) { + QString display = GetDisplay(); + if (!display.isEmpty()) { + int index = GetStandardValue(kViewInput).toInt(); + QStringList views = manager()->ListAvailableViews(display); + if (index < views.size()) { + return views.at(index); + } + } + } + return QString(); } -void DisplayTransformNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +ColorProcessor::Direction DisplayTransformNode::GetDirection() const { - ShaderJob job; - job.InsertValue(value); - job.SetUseOCIO(true); - job.SetShaderDesc(shader_desc_); - job.SetColorProcessor(reference_to_display_); + return static_cast(GetStandardValue(kDirectionInput).toInt());; +} - // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { - table->Push(NodeValue::kShaderJob, QVariant::fromValue(job), this); +void DisplayTransformNode::UpdateDisplays() +{ + if (manager()) { + SetComboBoxStrings(kDisplayInput, manager()->ListAvailableDisplays()); + } +} + +void DisplayTransformNode::UpdateViews() +{ + if (manager()) { + SetComboBoxStrings(kViewInput, manager()->ListAvailableViews(GetDisplay())); + } +} + +void DisplayTransformNode::ConfigChanged() +{ + UpdateDisplays(); + UpdateViews(); + GenerateProcessor(); +} + +void DisplayTransformNode::GenerateProcessor() +{ + if (manager()) { + ColorTransform transform(GetDisplay(), GetView(), QString()); + set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform, GetDirection())); } } diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h index b50e73e29..9c8dff5ba 100644 --- a/app/node/color/displaytransform/displaytransform.h +++ b/app/node/color/displaytransform/displaytransform.h @@ -1,35 +1,39 @@ /*** + 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 DISPLAYTRANSFORMNODE_H #define DISPLAYTRANSFORMNODE_H -#include "node/node.h" +#include "node/color/ociobase/ociobase.h" #include "render/colorprocessor.h" namespace olive { -class DisplayTransformNode : public Node { + +class DisplayTransformNode : public OCIOBaseNode +{ Q_OBJECT public: DisplayTransformNode(); NODE_DEFAULT_DESTRUCTOR(DisplayTransformNode) - - void GenerateProcessor(); - - virtual Node *copy() const override; + NODE_COPY_FUNCTION(DisplayTransformNode) virtual QString Name() const override; virtual QString id() const override; @@ -39,26 +43,26 @@ class DisplayTransformNode : public Node { virtual void Retranslate() override; 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; + QString GetDisplay() const; + QString GetView() const; + ColorProcessor::Direction GetDirection() const; - ColorProcessorPtr GetColorProcessor() { return reference_to_display_; }; - OCIO::GpuShaderDescRcPtr GetGPUShaderDesc() { return shader_desc_; }; - - static const QString kTextureInput; static const QString kDisplayInput; static const QString kViewInput; static const QString kDirectionInput; - const QString shader_text_; +protected slots: + virtual void ConfigChanged() override; - ColorProcessorPtr reference_to_display_; - OCIO::GpuShaderDescRcPtr shader_desc_; +private: + void GenerateProcessor(); + + void UpdateDisplays(); + + void UpdateViews(); - QString display_; - QString view_; }; } // olive -#endif +#endif // DISPLAYTRANSFORMNODE_H diff --git a/app/node/color/ociobase/CMakeLists.txt b/app/node/color/ociobase/CMakeLists.txt new file mode 100644 index 000000000..fa00411a4 --- /dev/null +++ b/app/node/color/ociobase/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/color/ociobase/ociobase.cpp + node/color/ociobase/ociobase.h + PARENT_SCOPE +) diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp new file mode 100644 index 000000000..db47c00ab --- /dev/null +++ b/app/node/color/ociobase/ociobase.cpp @@ -0,0 +1,65 @@ +/*** + + 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 . + +***/ + +#include "ociobase.h" + +#include "node/color/colormanager/colormanager.h" +#include "node/project/project.h" + +namespace olive { + +const QString OCIOBaseNode::kTextureInput = QStringLiteral("tex_in"); + +OCIOBaseNode::OCIOBaseNode() : + manager_(nullptr), + processor_(nullptr) +{ + AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + + connect(this, &Node::AddedToGraph, this, &OCIOBaseNode::ParentChanged); +} + +void OCIOBaseNode::ParentChanged(NodeGraph *graph) +{ + if (manager_) { + disconnect(manager_, &ColorManager::ConfigChanged, this, &OCIOBaseNode::ConfigChanged); + manager_ = nullptr; + } + + if (Project *p = dynamic_cast(graph)) { + manager_ = p->color_manager(); + connect(manager_, &ColorManager::ConfigChanged, this, &OCIOBaseNode::ConfigChanged); + ConfigChanged(); + } +} + +void OCIOBaseNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + if (!value[kTextureInput].data().isNull() && processor_) { + ColorTransformJob job; + + job.SetColorProcessor(processor_); + job.SetInputTexture(value[kTextureInput].data().value()); + + table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); + } +} + +} diff --git a/app/node/color/ociobase/ociobase.h b/app/node/color/ociobase/ociobase.h new file mode 100644 index 000000000..a0b6fc0f2 --- /dev/null +++ b/app/node/color/ociobase/ociobase.h @@ -0,0 +1,60 @@ +/*** + + 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 OCIOBASENODE_H +#define OCIOBASENODE_H + +#include "node/node.h" +#include "render/job/colortransformjob.h" + +namespace olive { + +class OCIOBaseNode : public Node +{ + Q_OBJECT +public: + OCIOBaseNode(); + + virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + + static const QString kTextureInput; + +protected slots: + virtual void ConfigChanged() = 0; + +protected: + ColorManager *manager() const { return manager_; } + + ColorProcessorPtr processor() const { return processor_; } + void set_processor(ColorProcessorPtr p) { processor_ = p; } + +private: + ColorManager *manager_; + + ColorProcessorPtr processor_; + +private slots: + void ParentChanged(olive::NodeGraph *graph); + +}; + +} + +#endif // OCIOBASENODE_H diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.cpp b/app/node/color/ociogradingtransform/ociogradingtransform.cpp index 10b63da54..27a8f57f0 100644 --- a/app/node/color/ociogradingtransform/ociogradingtransform.cpp +++ b/app/node/color/ociogradingtransform/ociogradingtransform.cpp @@ -1,16 +1,21 @@ /*** + 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 . + ***/ #include "ociogradingtransform.h" @@ -21,7 +26,6 @@ namespace olive { -const QString OCIOGradingTransformNode::kTextureInput = QStringLiteral("tex_in"); const QString OCIOGradingTransformNode::kTypeInput = QStringLiteral("type_in"); const QString OCIOGradingTransformNode::kBrightnessInput = QStringLiteral("brightness_in"); const QString OCIOGradingTransformNode::kContrastInput = QStringLiteral("contrast_in"); @@ -37,88 +41,39 @@ const QString OCIOGradingTransformNode::kPivotWhiteInput = QStringLiteral("pivot const QString OCIOGradingTransformNode::kClampBlackInput = QStringLiteral("clamp_black_in"); const QString OCIOGradingTransformNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); +#define super OCIOBaseNode + OCIOGradingTransformNode::OCIOGradingTransformNode() { - AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); - AddInput(kTypeInput, NodeValue::kCombo, 0); //AddInput(kBrightnessInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); - AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); + AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); //AddInput(kGammaInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); - AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); //AddInput(kLiftInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); //AddInput(kGainInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); - AddInput(kSaturationInput, NodeValue::kFloat, 1.0); + AddInput(kSaturationInput, NodeValue::kFloat, 1.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); - AddInput(kPivotInput, NodeValue::kFloat, 0.203919098); + AddInput(kPivotInput, NodeValue::kFloat, 0.203919098, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); // AddInput(kPivotBlackInput, NodeValue::kFloat, 0.0); //AddInput(kPivotWhiteInput, NodeValue::kFloat, 1.0); - AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); + AddInput(kClampBlackInput, NodeValue::kFloat, 0.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0); - - GenerateProcessor(); -} - -void OCIOGradingTransformNode::GenerateProcessor() -{ - if (!project()) { - return; - } - - // Create shader description - shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); - shader_desc_->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); - shader_desc_->setFunctionName("OCIOGradingTransform"); - shader_desc_->setResourcePrefix("ocio_"); - - OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); - //auto gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); - gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); - //gp->makeDynamic(); - - OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; - //gpdata.m_lift = OCIOUtils::QVec4ToRGBM(GetStandardValue(kLiftInput).value()); - gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); - gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); - //gpdata.m_gamma = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGammaInput).value()); - //gpdata.m_gain = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGainInput).value()); - gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); - gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); - gpdata.m_pivot = GetStandardValue(kPivotInput).value(); - gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); - gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); - //gpdata.m_pivotBlack = GetStandardValue(kPivotBlackInput).value(); - //gpdata.m_pivotWhite = GetStandardValue(kPivotWhiteInput).value(); - try { - gp->setValue(gpdata); - - processor_ = std::make_shared(); - processor_->SetProsessor(project()->color_manager()->GetConfig()->getProcessor(gp)); - } catch (const OCIO::Exception &e) { - std::cerr << std::endl << e.what() << std::endl; - } - - processor_->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc_); -} - -Node *OCIOGradingTransformNode::copy() const -{ - return new OCIOGradingTransformNode(); + AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); } QString OCIOGradingTransformNode::Name() const @@ -143,6 +98,8 @@ QString OCIOGradingTransformNode::Description() const void OCIOGradingTransformNode::Retranslate() { + super::Retranslate(); + SetInputName(kTextureInput, tr("Input")); SetInputName(kTypeInput, tr("Type")); //SetInputName(kBrightnessInput, tr("Brightness")); @@ -165,29 +122,35 @@ void OCIOGradingTransformNode::Retranslate() void OCIOGradingTransformNode::InputValueChangedEvent(const QString &input, int element) { Q_UNUSED(element); - GenerateProcessor(); + ConfigChanged(); } -ShaderCode OCIOGradingTransformNode::GetShaderCode(const QString &shader_id) const +void OCIOGradingTransformNode::ConfigChanged() { - Q_UNUSED(shader_id) - // Generate shader code using OCIO stub and our auto-generated name - QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/ociogradingtransform.frag")) - .arg(shader_desc_->getShaderText()); - return ShaderCode(shader_frag); -} + OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + //auto gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); + //gp->makeDynamic(); -void OCIOGradingTransformNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const -{ - ShaderJob job; - job.InsertValue(value); - job.SetUseOCIO(true); - job.SetShaderDesc(shader_desc_); - job.SetColorProcessor(processor_); + OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; + //gpdata.m_lift = OCIOUtils::QVec4ToRGBM(GetStandardValue(kLiftInput).value()); + gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); + gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); + //gpdata.m_gamma = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGammaInput).value()); + //gpdata.m_gain = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGainInput).value()); + gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); + gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); + gpdata.m_pivot = GetStandardValue(kPivotInput).value(); + gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); + gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); + //gpdata.m_pivotBlack = GetStandardValue(kPivotBlackInput).value(); + //gpdata.m_pivotWhite = GetStandardValue(kPivotWhiteInput).value(); + try { + gp->setValue(gpdata); - // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { - table->Push(NodeValue::kShaderJob, QVariant::fromValue(job), this); + set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp))); + } catch (const OCIO::Exception &e) { + std::cerr << std::endl << e.what() << std::endl; } } diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.h b/app/node/color/ociogradingtransform/ociogradingtransform.h index 6de018d14..99f2db214 100644 --- a/app/node/color/ociogradingtransform/ociogradingtransform.h +++ b/app/node/color/ociogradingtransform/ociogradingtransform.h @@ -1,35 +1,39 @@ /*** + 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 OCIOGRADINGTRANSFORMNODE_H #define OCIOGRADINGTRANSFORMNODE_H -#include "node/node.h" +#include "node/color/ociobase/ociobase.h" #include "render/colorprocessor.h" namespace olive { -class OCIOGradingTransformNode : public Node { + +class OCIOGradingTransformNode : public OCIOBaseNode +{ Q_OBJECT public: OCIOGradingTransformNode(); NODE_DEFAULT_DESTRUCTOR(OCIOGradingTransformNode) - - void GenerateProcessor(); - - virtual Node *copy() const override; + NODE_COPY_FUNCTION(OCIOGradingTransformNode) virtual QString Name() const override; virtual QString id() const override; @@ -39,13 +43,6 @@ class OCIOGradingTransformNode : public Node { virtual void Retranslate() override; 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; - - ColorProcessorPtr GetColorProcessor() { return processor_; }; - OCIO::GpuShaderDescRcPtr GetGPUShaderDesc() { return shader_desc_; }; - - static const QString kTextureInput; static const QString kTypeInput; static const QString kBrightnessInput; static const QString kContrastInput; @@ -61,13 +58,9 @@ class OCIOGradingTransformNode : public Node { static const QString kClampBlackInput; static const QString kClampWhiteInput; - const QString shader_text_; +protected slots: + virtual void ConfigChanged() override; - ColorProcessorPtr processor_; - OCIO::GpuShaderDescRcPtr shader_desc_; - - QString display_; - QString view_; }; } // olive diff --git a/app/node/hashtraverser.cpp b/app/node/hashtraverser.cpp index 155842242..cab012ad7 100644 --- a/app/node/hashtraverser.cpp +++ b/app/node/hashtraverser.cpp @@ -86,7 +86,7 @@ SampleBufferPtr HashTraverser::ProcessAudioFootage(const FootageJob &stream, con return buf; } -TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) +TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { HashGenerateJob(node, &job); @@ -104,6 +104,14 @@ TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range return texture; } +TexturePtr HashTraverser::ProcessColorTransform(const Node *node, const ColorTransformJob &job) +{ + Hash(job.GetColorProcessor()->id()); + TexturePtr texture = super::ProcessColorTransform(node, job); + texture_ids_.insert(texture.get(), hash_.result()); + return texture; +} + SampleBufferPtr HashTraverser::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) { SampleBufferPtr buf = super::ProcessSamples(node, range, job); diff --git a/app/node/hashtraverser.h b/app/node/hashtraverser.h index 39957c9ed..a7bfe6b84 100644 --- a/app/node/hashtraverser.h +++ b/app/node/hashtraverser.h @@ -37,7 +37,9 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time) override; - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job) override; + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; + + virtual TexturePtr ProcessColorTransform(const Node *node, const ColorTransformJob& job) override; virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index d32941253..677f3ce99 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -292,7 +292,7 @@ SampleBufferPtr NodeTraverser::ProcessAudioFootage(const FootageJob& stream, con return SampleBuffer::Create(); } -TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) +TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { Q_UNUSED(node) Q_UNUSED(range) @@ -304,6 +304,13 @@ TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range return CreateDummyTexture(tex_params); } +TexturePtr NodeTraverser::ProcessColorTransform(const Node *node, const ColorTransformJob &job) +{ + Q_UNUSED(node) + + return CreateDummyTexture(job.GetInputTexture()->params()); +} + SampleBufferPtr NodeTraverser::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) { Q_UNUSED(node) @@ -366,6 +373,7 @@ void NodeTraverser::PostProcessTable(const Node *node, const Node::ValueHint &hi QList shader_jobs_to_run; QList sample_jobs_to_run; QList generate_jobs_to_run; + QList color_transform_jobs_to_run; for (int i=0; i())), node, v.array(), v.tag()); } + // Run color transforms + foreach (const NodeValue& v, color_transform_jobs_to_run) { + output_params.Push(NodeValue::kTexture, QVariant::fromValue(ProcessColorTransform(node, v.data().value())), node, v.array(), v.tag()); + } + // Run generate jobs foreach (const NodeValue& v, generate_jobs_to_run) { output_params.Push(NodeValue::kTexture, QVariant::fromValue(ProcessFrameGeneration(node, v.data().value())), node, v.array(), v.tag()); diff --git a/app/node/traverser.h b/app/node/traverser.h index 3af7a300c..925e37552 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -27,6 +27,7 @@ #include "common/cancelableobject.h" #include "node/output/track/track.h" #include "render/job/footagejob.h" +#include "render/job/colortransformjob.h" #include "value.h" namespace olive { @@ -76,7 +77,9 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time); - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job); + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job); + + virtual TexturePtr ProcessColorTransform(const Node *node, const ColorTransformJob& job); virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job); diff --git a/app/node/value.cpp b/app/node/value.cpp index d3fa7373b..3eed697a5 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -141,6 +141,7 @@ QByteArray NodeValue::ValueToBytes(NodeValue::Type type, const QVariant &value) case kShaderJob: case kSampleJob: case kGenerateJob: + case kColorTransformJob: case kDataTypeCount: break; } @@ -358,6 +359,7 @@ QString NodeValue::GetPrettyDataTypeName(Type type) case kShaderJob: case kSampleJob: case kGenerateJob: + case kColorTransformJob: case kDataTypeCount: break; } @@ -410,6 +412,7 @@ QString NodeValue::GetDataTypeName(Type type) case kShaderJob: case kSampleJob: case kGenerateJob: + case kColorTransformJob: case kDataTypeCount: break; } diff --git a/app/node/value.h b/app/node/value.h index 12fb91a33..e949bbca9 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -208,6 +208,15 @@ public: */ kGenerateJob, + /** + * Job type + * + * An internal type used to indicate to the renderer that an accelerated color transform job + * needs to take place. This value will usually be taken from a table and a kTexture value will + * be pushed to take its place. + */ + kColorTransformJob, + /** * End of list */ diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 6080aae54..b7349e4b2 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -25,11 +25,8 @@ #include "node/color/colormanager/colormanager.h" namespace olive { -ColorProcessor::ColorProcessor() -{ -} -ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const ColorTransform &transform) +ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const ColorTransform &transform, Direction direction) { QMutexLocker locker(config->mutex()); @@ -44,6 +41,7 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const display_transform->setSrc(input.toUtf8()); display_transform->setDisplay(output.toUtf8()); display_transform->setView(view.toUtf8()); + display_transform->setDirection(direction == kNormal ? OCIO::TRANSFORM_DIR_FORWARD : OCIO::TRANSFORM_DIR_INVERSE); OCIO_SET_C_LOCALE_FOR_SCOPE; @@ -73,7 +71,11 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const OCIO_SET_C_LOCALE_FOR_SCOPE; try { - processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); + if (direction == kNormal) { + processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); + } else { + processor_ = config->GetConfig()->getProcessor(output.toUtf8(), input.toUtf8()); + } } catch (OCIO::Exception &e) { qWarning() << "ColorProcessor exception:" << e.what(); } @@ -81,7 +83,12 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const } cpu_processor_ = processor_->getDefaultCPUProcessor(); - id_ = GenerateID(config, input, transform); +} + +ColorProcessor::ColorProcessor(OCIO::ConstProcessorRcPtr processor) +{ + processor_ = processor; + cpu_processor_ = processor_->getDefaultCPUProcessor(); } void ColorProcessor::ConvertFrame(Frame *f) @@ -115,18 +122,14 @@ Color ColorProcessor::ConvertColor(const Color& in) return Color(c[0], c[1], c[2], c[3]); } -QString ColorProcessor::GenerateID(ColorManager *config, const QString &input, const ColorTransform &transform) +ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform, Direction direction) { - return QStringLiteral("%1:%2:%3:%4:%5").arg(config->GetConfigFilename(), - input, - transform.display(), - transform.view(), - transform.look()); + return std::make_shared(config, input, transform, direction); } -ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform) +ColorProcessorPtr ColorProcessor::Create(OCIO::ConstProcessorRcPtr processor) { - return std::make_shared(config, input, transform); + return std::make_shared(processor); } OCIO::ConstProcessorRcPtr ColorProcessor::GetProcessor() diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h index 9a7c5552b..9d1c9130a 100644 --- a/app/render/colorprocessor.h +++ b/app/render/colorprocessor.h @@ -41,35 +41,31 @@ public: kInverse }; - ColorProcessor(ColorManager* config, const QString& input, const ColorTransform& dest_space); - ColorProcessor(); + ColorProcessor(ColorManager* config, const QString& input, const ColorTransform& dest_space, Direction direction = kNormal); + ColorProcessor(OCIO::ConstProcessorRcPtr processor); DISABLE_COPY_MOVE(ColorProcessor) - static ColorProcessorPtr Create(ColorManager* config, const QString& input, const ColorTransform& dest_space); + static ColorProcessorPtr Create(ColorManager* config, const QString& input, const ColorTransform& dest_space, Direction direction = kNormal); + static ColorProcessorPtr Create(OCIO::ConstProcessorRcPtr processor); OCIO::ConstProcessorRcPtr GetProcessor(); - void SetProsessor(OCIO::ConstProcessorRcPtr processor) { processor_ = processor; }; void ConvertFrame(FramePtr f); void ConvertFrame(Frame* f); Color ConvertColor(const Color &in); - const QString& id() const + const char *id() const { - return id_; + return processor_->getCacheID(); } - static QString GenerateID(ColorManager* config, const QString& input, const ColorTransform& dest_space); - private: OCIO::ConstProcessorRcPtr processor_; OCIO::ConstCPUProcessorRcPtr cpu_processor_; - QString id_; - }; using ColorProcessorChain = QVector; diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h new file mode 100644 index 000000000..cf653d27e --- /dev/null +++ b/app/render/job/colortransformjob.h @@ -0,0 +1,54 @@ +/*** + + 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 COLORTRANSFORMJOB_H +#define COLORTRANSFORMJOB_H + +#include "render/colorprocessor.h" +#include "render/texture.h" + +namespace olive { + +class ColorTransformJob { +public: + ColorTransformJob() + { + processor_ = nullptr; + input_texture_ = nullptr; + } + + TexturePtr GetInputTexture() const { return input_texture_; } + void SetInputTexture(TexturePtr tex) { input_texture_ = tex; } + + ColorProcessorPtr GetColorProcessor() const { return processor_; } + void SetColorProcessor(ColorProcessorPtr p) { processor_ = p; } + +private: + ColorProcessorPtr processor_; + + TexturePtr input_texture_; + +}; + +} + +Q_DECLARE_METATYPE(olive::ColorTransformJob) + +#endif // COLORTRANSFORMJOB_H diff --git a/app/render/job/shaderjob.h b/app/render/job/shaderjob.h index 335d442b5..53cd836d6 100644 --- a/app/render/job/shaderjob.h +++ b/app/render/job/shaderjob.h @@ -36,7 +36,6 @@ public: { iterations_ = 1; iterative_input_ = nullptr; - use_ocio_ = false; } const QString& GetShaderID() const @@ -90,36 +89,6 @@ public: interpolation_.insert(id, interp); } - bool UseOCIO() const - { - return use_ocio_; - } - - void SetUseOCIO(bool use_ocio) - { - use_ocio_ = use_ocio; - } - - ColorProcessorPtr ColorProcessor() - { - return color_processor_; - } - - void SetColorProcessor(ColorProcessorPtr processor) - { - color_processor_ = processor; - } - - OCIO::GpuShaderDescRcPtr ShaderDesc() - { - return shader_desc_; - } - - void SetShaderDesc(OCIO::GpuShaderDescRcPtr shader_desc) - { - shader_desc_ = shader_desc; - } - void SetVertexCoordinates(const QVector &vertex_coords) { vertex_overrides_ = vertex_coords; @@ -139,12 +108,6 @@ private: QHash interpolation_; - bool use_ocio_; - - ColorProcessorPtr color_processor_; - - OCIO::GpuShaderDescRcPtr shader_desc_; - QVector vertex_overrides_; }; diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index 8d9786973..f762c480e 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -523,6 +523,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video case NodeValue::kFootageJob: case NodeValue::kBezier: case NodeValue::kNone: + case NodeValue::kColorTransformJob: case NodeValue::kDataTypeCount: break; } diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 844624f38..b78df3df4 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -62,23 +62,6 @@ void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr so BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix); } -void Renderer::ShaderJobInsertTextures(ColorProcessorPtr color_processor, ShaderJob* job, - OCIO::GpuShaderDescRcPtr shader_desc) { - ColorContext color_ctx; - if (!GetCustomColorContext(color_processor, &color_ctx, shader_desc)) { - return; - } - - foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { - job->InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); - job->SetInterpolation(l.name, l.interpolation); - } - foreach (const ColorContext::LUT& l, color_ctx.lut1d_textures) { - job->InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); - job->SetInterpolation(l.name, l.interpolation); - } -} - TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms) { color_cache_mutex_.lock(); @@ -120,96 +103,6 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const Vide return std::make_shared(this, v, params, type); } -bool Renderer::GetCustomColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext* ctx, - OCIO::GpuShaderDescRcPtr shader_desc) { - QMutexLocker locker(&color_cache_mutex_); - - ColorContext& color_ctx = *ctx; - - if (color_cache_.contains(color_processor->id())) { - color_ctx = color_cache_.value(color_processor->id()); - return true; - } else { - if (SetupColorContextTextures(color_ctx, shader_desc, color_processor)) { - return true; - } else { - qCritical() << "Failed to allocate OCIO shader textures"; - return false; - } - } -} - -bool Renderer::SetupColorContextTextures(ColorContext& color_ctx, OCIO::ConstGpuShaderDescRcPtr shader_desc, - ColorProcessorPtr color_processor) -{ - color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); - for (unsigned int i = 0; i < shader_desc->getNum3DTextures(); i++) { - const char* tex_name = nullptr; - const char* sampler_name = nullptr; - unsigned int edge_len = 0; - OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; - - shader_desc->get3DTexture(i, tex_name, sampler_name, edge_len, interpolation); - - if (!tex_name || !*tex_name || !sampler_name || !*sampler_name || !edge_len) { - qCritical() << "3D LUT texture data is corrupted"; - return false; - } - - const float* values = nullptr; - shader_desc->get3DTextureValues(i, values); - if (!values) { - qCritical() << "3D LUT texture values are missing"; - return false; - } - - // Allocate 3D LUT - color_ctx.lut3d_textures[i].texture = CreateTexture( - VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), - Texture::k3D, values); - color_ctx.lut3d_textures[i].name = sampler_name; - color_ctx.lut3d_textures[i].interpolation = - (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; - } - - color_ctx.lut1d_textures.resize(shader_desc->getNumTextures()); - for (unsigned int i = 0; i < shader_desc->getNumTextures(); i++) { - const char* tex_name = nullptr; - const char* sampler_name = nullptr; - unsigned int width = 0, height = 0; - OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL; - OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; - - shader_desc->getTexture(i, tex_name, sampler_name, width, height, channel, interpolation); - - if (!tex_name || !*tex_name || !sampler_name || !*sampler_name || !width) { - qCritical() << "1D LUT texture data is corrupted"; - return false; - } - - const float* values = nullptr; - shader_desc->getTextureValues(i, values); - if (!values) { - qCritical() << "1D LUT texture values are missing"; - return false; - } - - // Allocate 1D LUT - color_ctx.lut1d_textures[i].texture = CreateTexture( - VideoParams(width, height, VideoParams::kFormatFloat32, - (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), - Texture::k2D, values); - color_ctx.lut1d_textures[i].name = sampler_name; - color_ctx.lut1d_textures[i].interpolation = - (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; - } - - color_cache_.insert(color_processor->id(), color_ctx); - - return true; - -} - bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx) { QMutexLocker locker(&color_cache_mutex_); @@ -244,12 +137,71 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo return false; } - if (SetupColorContextTextures(color_ctx, shader_desc, color_processor)) { - return true; - } else { - qCritical() << "Failed to allocate OCIO shader textures"; - return false; + color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); + for (unsigned int i=0; igetNum3DTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int edge_len = 0; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->get3DTexture(i, tex_name, sampler_name, edge_len, interpolation); + + if (!tex_name || !*tex_name + || !sampler_name || !*sampler_name + || !edge_len) { + qCritical() << "3D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->get3DTextureValues(i, values); + if (!values) { + qCritical() << "3D LUT texture values are missing"; + return false; + } + + // Allocate 3D LUT + color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), + Texture::k3D, values); + color_ctx.lut3d_textures[i].name = sampler_name; + color_ctx.lut3d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; } + + color_ctx.lut1d_textures.resize(shader_desc->getNumTextures()); + for (unsigned int i=0; igetNumTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int width = 0, height = 0; + OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->getTexture(i, tex_name, sampler_name, width, height, channel, interpolation); + + if (!tex_name || !*tex_name + || !sampler_name || !*sampler_name + || !width) { + qCritical() << "1D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->getTextureValues(i, values); + if (!values) { + qCritical() << "1D LUT texture values are missing"; + return false; + } + + // Allocate 1D LUT + color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, VideoParams::kFormatFloat32, (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), + Texture::k2D, + values); + color_ctx.lut1d_textures[i].name = sampler_name; + color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; + } + + color_cache_.insert(color_processor->id(), color_ctx); + + return true; } } diff --git a/app/render/renderer.h b/app/render/renderer.h index ef41dfa93..977fc98ce 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -63,8 +63,6 @@ public: Blit(shader, job, nullptr, params, clear_destination); } - void ShaderJobInsertTextures(ColorProcessorPtr color_processor, ShaderJob* job, OCIO::GpuShaderDescRcPtr shader_desc); - enum AlphaAssociated { kAlphaNone, kAlphaUnassociated, @@ -130,12 +128,6 @@ private: bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx); - bool GetCustomColorContext(ColorProcessorPtr color_processor, ColorContext* ctx, - OCIO::GpuShaderDescRcPtr shader_desc); - - bool SetupColorContextTextures(ColorContext& color_ctx, OCIO::ConstGpuShaderDescRcPtr shader_desc, - ColorProcessorPtr color_processor); - void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, VideoParams params, bool clear_destination, diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 7017a7c11..f223824cb 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -496,7 +496,7 @@ SampleBufferPtr RenderProcessor::ProcessAudioFootage(const FootageJob &stream, c return super::ProcessAudioFootage(stream, input_time); } -TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) +TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { Q_UNUSED(range) @@ -507,9 +507,10 @@ TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &ran QVariant shader = shader_cache_->value(full_shader_id); if (shader.isNull()) { - if (job.UseOCIO()) { - render_ctx_->ShaderJobInsertTextures(job.ColorProcessor(), &job, job.ShaderDesc()); - } + // FIXME: Reimplement as color job + //if (job.UseOCIO()) { + // render_ctx_->ShaderJobInsertTextures(job.ColorProcessor(), &job, job.ShaderDesc()); + //} // Since we have shader code, compile it now shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID())); @@ -565,6 +566,16 @@ SampleBufferPtr RenderProcessor::ProcessSamples(const Node *node, const TimeRang return output_buffer; } +TexturePtr RenderProcessor::ProcessColorTransform(const Node *node, const ColorTransformJob &job) +{ + TexturePtr src = job.GetInputTexture(); + TexturePtr dest = render_ctx_->CreateTexture(src->params()); + + render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get()); + + return dest; +} + TexturePtr RenderProcessor::ProcessFrameGeneration(const Node *node, const GenerateJob &job) { FramePtr frame = Frame::Create(); diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 7d655a986..a1ee8a747 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -48,10 +48,12 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time) override; - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job) override; + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; + virtual TexturePtr ProcessColorTransform(const Node *node, const ColorTransformJob& job) override; + virtual TexturePtr ProcessFrameGeneration(const Node *node, const GenerateJob& job) override; virtual bool CanCacheFrames() override; diff --git a/app/shaders/displaytransform.frag b/app/shaders/displaytransform.frag deleted file mode 100644 index d597f47d2..000000000 --- a/app/shaders/displaytransform.frag +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D tex_in; -varying vec2 ove_texcoord; - -// Program will replace this with OCIO's auto-generated shader code -%1 - -void main() { - vec4 col = texture2D(tex_in, ove_texcoord); - - col = DisplayTransform(col); - - gl_FragColor = col; -} diff --git a/app/shaders/ociogradingtransform.frag b/app/shaders/ociogradingtransform.frag deleted file mode 100644 index ca1841dc2..000000000 --- a/app/shaders/ociogradingtransform.frag +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D tex_in; -varying vec2 ove_texcoord; - -// Program will replace this with OCIO's auto-generated shader code -%1 - -void main() { - vec4 col = texture2D(tex_in, ove_texcoord); - - col = OCIOGradingTransform(col); - - gl_FragColor = col; -} diff --git a/app/shaders/stub.frag b/app/shaders/stub.frag new file mode 100644 index 000000000..ccc1b86dd --- /dev/null +++ b/app/shaders/stub.frag @@ -0,0 +1,13 @@ +uniform sampler2D tex_in; +in vec2 ove_texcoord; +out vec4 frag_color; + +%1 + +void main() { + vec4 col = texture2D(tex_in, ove_texcoord); + + col = %2(col); + + frag_color = col; +} diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 29c35657b..3413a2f2e 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -90,6 +90,7 @@ void NodeParamViewWidgetBridge::CreateWidgets() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: + case NodeValue::kColorTransformJob: case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kDataTypeCount: @@ -244,6 +245,7 @@ void NodeParamViewWidgetBridge::WidgetCallback() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: + case NodeValue::kColorTransformJob: case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kDataTypeCount: @@ -421,6 +423,7 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: + case NodeValue::kColorTransformJob: case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kDataTypeCount: