From c0d8ff403f86743af3fca5e537b76f65673c6c3f Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 24 Sep 2022 18:44:59 -0700 Subject: [PATCH] nodes: rework so that jobs can be completely deferred Big optimization requiring a lot of refactoring. --- app/codec/encoder.h | 1 + app/core.cpp | 3 - .../diptocolor/diptocolortransition.cpp | 4 +- .../diptocolor/diptocolortransition.h | 2 +- app/node/block/transition/transition.cpp | 4 +- app/node/block/transition/transition.h | 2 +- app/node/color/ociobase/ociobase.cpp | 8 +- .../ociogradingtransformlinear.cpp | 72 ++--- .../cornerpin/cornerpindistortnode.cpp | 95 +++--- app/node/distort/crop/cropdistortnode.cpp | 40 +-- app/node/distort/crop/cropdistortnode.h | 1 + app/node/distort/flip/flipdistortnode.cpp | 12 +- app/node/distort/mask/mask.cpp | 15 +- app/node/distort/ripple/rippledistortnode.cpp | 22 +- app/node/distort/swirl/swirldistortnode.cpp | 17 +- app/node/distort/tile/tiledistortnode.cpp | 57 ++-- .../transform/transformdistortnode.cpp | 17 +- app/node/distort/wave/wavedistortnode.cpp | 12 +- app/node/effect/opacity/opacityeffect.cpp | 12 +- app/node/filter/blur/blur.cpp | 44 +-- .../filter/dropshadow/dropshadowfilter.cpp | 9 +- app/node/filter/mosaic/mosaicfilternode.cpp | 24 +- app/node/filter/stroke/stroke.cpp | 17 +- app/node/generator/noise/noise.cpp | 6 +- app/node/generator/polygon/polygon.cpp | 22 +- app/node/generator/polygon/polygon.h | 2 +- .../generator/shape/generatorwithmerge.cpp | 8 +- app/node/generator/shape/generatorwithmerge.h | 2 +- app/node/generator/shape/shapenode.cpp | 9 +- app/node/generator/shape/shapenodebase.cpp | 4 +- app/node/generator/solid/solid.cpp | 4 +- app/node/generator/text/textv1.cpp | 7 +- app/node/generator/text/textv2.cpp | 11 +- app/node/generator/text/textv3.cpp | 22 +- app/node/globals.h | 6 +- app/node/keying/chromakey/chromakey.cpp | 17 +- .../colordifferencekey/colordifferencekey.cpp | 9 +- app/node/keying/despill/despill.cpp | 4 +- app/node/math/math/mathbase.cpp | 4 +- app/node/math/merge/merge.cpp | 12 +- app/node/project/footage/footage.cpp | 17 +- app/node/traverser.cpp | 294 ++++++++---------- app/node/traverser.h | 21 +- app/node/value.h | 5 + app/render/job/acceleratedjob.h | 5 +- app/render/job/cachejob.h | 15 +- app/render/job/colortransformjob.h | 24 +- app/render/job/footagejob.h | 2 +- app/render/job/generatejob.h | 25 +- app/render/job/samplejob.h | 3 +- app/render/job/shaderjob.h | 20 +- app/render/opengl/openglrenderer.cpp | 1 + app/render/renderer.cpp | 2 +- app/render/renderprocessor.cpp | 51 +-- app/render/renderprocessor.h | 12 +- app/render/texture.cpp | 4 + app/render/texture.h | 41 ++- 57 files changed, 593 insertions(+), 588 deletions(-) diff --git a/app/codec/encoder.h b/app/codec/encoder.h index e33f1de9a..e27cd1417 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -33,6 +33,7 @@ #include "common/timerange.h" #include "node/block/subtitle/subtitle.h" #include "render/audioparams.h" +#include "render/colortransform.h" #include "render/subtitleparams.h" #include "render/videoparams.h" diff --git a/app/core.cpp b/app/core.cpp index 97a49f8e0..0a90e92d4 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -116,9 +116,6 @@ void Core::DeclareTypesForQt() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index f9945dad0..5b262288e 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -56,9 +56,9 @@ ShaderCode DipToColorTransition::GetShaderCode(const ShaderRequest &request) con return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/diptoblack.frag"), QString()); } -void DipToColorTransition::ShaderJobEvent(const NodeValueRow &value, ShaderJob &job) const +void DipToColorTransition::ShaderJobEvent(const NodeValueRow &value, ShaderJob *job) const { - job.Insert(kColorInput, value); + job->Insert(kColorInput, value); } } diff --git a/app/node/block/transition/diptocolor/diptocolortransition.h b/app/node/block/transition/diptocolor/diptocolortransition.h index c1f3dca0f..f0554f6c7 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.h +++ b/app/node/block/transition/diptocolor/diptocolortransition.h @@ -43,7 +43,7 @@ public: static const QString kColorInput; protected: - virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const override; + virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob *job) const override; }; diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index f8b86d67d..d5c048eeb 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -182,10 +182,10 @@ void TransitionBlock::Value(const NodeValueRow &value, const NodeGlobals &global double time = globals.time().in().toDouble(); InsertTransitionTimes(&job, time); - ShaderJobEvent(value, job); + ShaderJobEvent(value, &job); job_type = NodeValue::kTexture; - push_job = QVariant::fromValue(job); + push_job = QVariant::fromValue(Texture::Job(globals.vparams(), job)); } else if (data_type == NodeValue::kSamples) { // This must be an audio transition SampleBuffer from_samples = out_buffer.toSamples(); diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index 0babf1516..554a7c469 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -73,7 +73,7 @@ public: static const QString kCenterInput; protected: - virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const {} + virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob *job) const {} virtual void SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const {} diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp index 831c2f8be..498596b68 100644 --- a/app/node/color/ociobase/ociobase.cpp +++ b/app/node/color/ociobase/ociobase.cpp @@ -60,13 +60,15 @@ void OCIOBaseNode::RemovedFromGraph() void OCIOBaseNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - if (value[kTextureInput].toTexture() && processor_) { + auto tex_met = value[kTextureInput]; + TexturePtr t = tex_met.toTexture(); + if (t && processor_) { ColorTransformJob job; job.SetColorProcessor(processor_); - job.SetInputTexture(value[kTextureInput].toTexture()); + job.SetInputTexture(tex_met); - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, t->toJob(job), this); } } diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 2ef925652..a6a37012f 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -155,50 +155,50 @@ void OCIOGradingTransformLinearNode::GenerateProcessor() void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - if (value[kTextureInput].toTexture() && processor()) { - ColorTransformJob job; + if (TexturePtr tex = value[kTextureInput].toTexture()) { + if (processor()) { + ColorTransformJob job(value); - job.SetColorProcessor(processor()); - job.SetInputTexture(value[kTextureInput].toTexture()); + job.SetColorProcessor(processor()); + job.SetInputTexture(value[kTextureInput]); - job.Insert(value); + const int MASTER_CHANNEL = 0; + const int RED_CHANNEL = 1; + const int GREEN_CHANNEL = 2; + const int BLUE_CHANNEL = 3; - const int MASTER_CHANNEL = 0; - const int RED_CHANNEL = 1; - const int GREEN_CHANNEL = 2; - const int BLUE_CHANNEL = 3; + // Oddly, OCIO uses RGBMs when setting the GradingPrimary on the CPU, but uses vec3s on the GPU. + // Even more oddly, the conversion from RGBM to vec3 does not appear to have a public API. + // Therefore, this code has been duplicated from OCIO here: + // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/3abbe5b20521169580fcfe3692aca81859859953/src/OpenColorIO/ops/gradingprimary/GradingPrimary.cpp#L157 + QVector4D offset = value[kOffsetInput].toVec4(); + offset[RED_CHANNEL] += offset[MASTER_CHANNEL]; + offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL]; + offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL]; + job.Insert(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL]))); - // Oddly, OCIO uses RGBMs when setting the GradingPrimary on the CPU, but uses vec3s on the GPU. - // Even more oddly, the conversion from RGBM to vec3 does not appear to have a public API. - // Therefore, this code has been duplicated from OCIO here: - // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/3abbe5b20521169580fcfe3692aca81859859953/src/OpenColorIO/ops/gradingprimary/GradingPrimary.cpp#L157 - QVector4D offset = value[kOffsetInput].toVec4(); - offset[RED_CHANNEL] += offset[MASTER_CHANNEL]; - offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL]; - offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL]; - job.Insert(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL]))); + QVector4D exposure = value[kExposureInput].toVec4(); + exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]); + exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]); + exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]); + job.Insert(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL]))); - QVector4D exposure = value[kExposureInput].toVec4(); - exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]); - exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]); - exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]); - job.Insert(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL]))); + QVector4D contrast = value[kContrastInput].toVec4(); + contrast[RED_CHANNEL] *= contrast[MASTER_CHANNEL]; + contrast[GREEN_CHANNEL] *= contrast[MASTER_CHANNEL]; + contrast[BLUE_CHANNEL] *= contrast[MASTER_CHANNEL]; + job.Insert(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL]))); - QVector4D contrast = value[kContrastInput].toVec4(); - contrast[RED_CHANNEL] *= contrast[MASTER_CHANNEL]; - contrast[GREEN_CHANNEL] *= contrast[MASTER_CHANNEL]; - contrast[BLUE_CHANNEL] *= contrast[MASTER_CHANNEL]; - job.Insert(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL]))); + if (!value[kClampBlackEnableInput].toBool()) { + job.Insert(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack())); + } - if (!value[kClampBlackEnableInput].toBool()) { - job.Insert(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack())); + if (!value[kClampWhiteEnableInput].toBool()) { + job.Insert(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite())); + } + + table->Push(NodeValue::kTexture, tex->toJob(job), this); } - - if (!value[kClampWhiteEnableInput].toBool()) { - job.Insert(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite())); - } - - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } diff --git a/app/node/distort/cornerpin/cornerpindistortnode.cpp b/app/node/distort/cornerpin/cornerpindistortnode.cpp index 38fc58104..2bb8a4a90 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.cpp +++ b/app/node/distort/cornerpin/cornerpindistortnode.cpp @@ -69,40 +69,39 @@ void CornerPinDistortNode::Retranslate() void CornerPinDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - - // Convert slider values to their pixel values and then convert to clip space (-1.0 ... 1.0) for overriding the - // vertex coordinates. - const QVector2D &resolution = globals.resolution(); - QVector2D half_resolution = resolution * 0.5; - QVector2D top_left = QVector2D(ValueToPixel(0, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); - QVector2D top_right = QVector2D(ValueToPixel(1, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); - QVector2D bottom_right = QVector2D(ValueToPixel(2, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); - QVector2D bottom_left = QVector2D(ValueToPixel(3, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); - - // Override default vertex coordinates. - QVector adjusted_vertices = {top_left.x(), top_left.y(), 0.0f, - top_right.x(), top_right.y(), 0.0f, - bottom_right.x(), bottom_right.y(), 0.0f, - - top_left.x(), top_left.y(), 0.0f, - bottom_left.x(), bottom_left.y(), 0.0f, - bottom_right.x(), bottom_right.y(), 0.0f}; - job.SetVertexCoordinates(adjusted_vertices); - // If no texture do nothing - if (job.Get(kTextureInput).toTexture()) { + if (TexturePtr tex = value[kTextureInput].toTexture()) { // In the special case that all sliders are in their default position just // push the texture. - if (!(job.Get(kTopLeftInput).toVec2().isNull() - && job.Get(kTopRightInput).toVec2().isNull() && - job.Get(kBottomRightInput).toVec2().isNull() && - job.Get(kBottomLeftInput).toVec2().isNull())) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (!(value[kTopLeftInput].toVec2().isNull() + && value[kTopRightInput].toVec2().isNull() && + value[kBottomRightInput].toVec2().isNull() && + value[kBottomLeftInput].toVec2().isNull())) { + ShaderJob job(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this)); + + // Convert slider values to their pixel values and then convert to clip space (-1.0 ... 1.0) for overriding the + // vertex coordinates. + const QVector2D &resolution = tex->virtual_resolution(); + QVector2D half_resolution = resolution * 0.5; + QVector2D top_left = QVector2D(ValueToPixel(0, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); + QVector2D top_right = QVector2D(ValueToPixel(1, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); + QVector2D bottom_right = QVector2D(ValueToPixel(2, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); + QVector2D bottom_left = QVector2D(ValueToPixel(3, value, resolution)) / half_resolution - QVector2D(1.0, 1.0); + + // Override default vertex coordinates. + QVector adjusted_vertices = {top_left.x(), top_left.y(), 0.0f, + top_right.x(), top_right.y(), 0.0f, + bottom_right.x(), bottom_right.y(), 0.0f, + + top_left.x(), top_left.y(), 0.0f, + bottom_left.x(), bottom_left.y(), 0.0f, + bottom_right.x(), bottom_right.y(), 0.0f}; + job.SetVertexCoordinates(adjusted_vertices); + + table->Push(NodeValue::kTexture, tex->toJob(job), this); } else { - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } @@ -151,27 +150,29 @@ void CornerPinDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardM void CornerPinDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - const QVector2D &resolution = globals.resolution(); + if (TexturePtr tex = row[kTextureInput].toTexture()) { + const QVector2D &resolution = tex->virtual_resolution(); - QPointF top_left = ValueToPixel(0, row, resolution); - QPointF top_right = ValueToPixel(1, row, resolution); - QPointF bottom_right = ValueToPixel(2, row, resolution); - QPointF bottom_left = ValueToPixel(3, row, resolution); + QPointF top_left = ValueToPixel(0, row, resolution); + QPointF top_right = ValueToPixel(1, row, resolution); + QPointF bottom_right = ValueToPixel(2, row, resolution); + QPointF bottom_left = ValueToPixel(3, row, resolution); - // Add the correct offset to each slider - SetInputProperty(kTopLeftInput, QStringLiteral("offset"), QVector2D(0.0, 0.0)); - SetInputProperty(kTopRightInput, QStringLiteral("offset"), QVector2D(resolution.x() , 0.0)); - SetInputProperty(kBottomRightInput, QStringLiteral("offset"), resolution); - SetInputProperty(kBottomLeftInput, QStringLiteral("offset"), QVector2D(0.0, resolution.y())); + // Add the correct offset to each slider + SetInputProperty(kTopLeftInput, QStringLiteral("offset"), QVector2D(0.0, 0.0)); + SetInputProperty(kTopRightInput, QStringLiteral("offset"), QVector2D(resolution.x() , 0.0)); + SetInputProperty(kBottomRightInput, QStringLiteral("offset"), resolution); + SetInputProperty(kBottomLeftInput, QStringLiteral("offset"), QVector2D(0.0, resolution.y())); - // Draw bounding box - gizmo_whole_rect_->SetPolygon(QPolygonF({top_left, top_right, bottom_right, bottom_left, top_left})); + // Draw bounding box + gizmo_whole_rect_->SetPolygon(QPolygonF({top_left, top_right, bottom_right, bottom_left, top_left})); - // Create handles - gizmo_resize_handle_[0]->SetPoint(top_left); - gizmo_resize_handle_[1]->SetPoint(top_right); - gizmo_resize_handle_[2]->SetPoint(bottom_right); - gizmo_resize_handle_[3]->SetPoint(bottom_left); + // Create handles + gizmo_resize_handle_[0]->SetPoint(top_left); + gizmo_resize_handle_[1]->SetPoint(top_right); + gizmo_resize_handle_[2]->SetPoint(bottom_right); + gizmo_resize_handle_[3]->SetPoint(bottom_left); + } } } diff --git a/app/node/distort/crop/cropdistortnode.cpp b/app/node/distort/crop/cropdistortnode.cpp index b5bbbef1a..1d2dfd4e3 100644 --- a/app/node/distort/crop/cropdistortnode.cpp +++ b/app/node/distort/crop/cropdistortnode.cpp @@ -79,7 +79,6 @@ void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global { ShaderJob job; job.Insert(value); - job.SetWillChangeImageSize(false); if (TexturePtr texture = job.Get(kTextureInput).toTexture()) { job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture->params().width(), texture->params().height()), this)); @@ -88,7 +87,7 @@ void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global || !qIsNull(job.Get(kRightInput).toDouble()) || !qIsNull(job.Get(kTopInput).toDouble()) || !qIsNull(job.Get(kBottomInput).toDouble())) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, texture->toJob(job), this); } else { table->Push(job.Get(kTextureInput)); } @@ -103,32 +102,35 @@ ShaderCode CropDistortNode::GetShaderCode(const ShaderRequest &request) const void CropDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - const QVector2D &resolution = globals.resolution(); + if (TexturePtr tex = row[kTextureInput].toTexture()) { + const QVector2D &resolution = tex->virtual_resolution(); + temp_resolution_ = resolution; - double left_pt = resolution.x() * row[kLeftInput].toDouble(); - double top_pt = resolution.y() * row[kTopInput].toDouble(); - double right_pt = resolution.x() * (1.0 - row[kRightInput].toDouble()); - double bottom_pt = resolution.y() * (1.0 - row[kBottomInput].toDouble()); - double center_x_pt = mid(left_pt, right_pt); - double center_y_pt = mid(top_pt, bottom_pt); + double left_pt = resolution.x() * row[kLeftInput].toDouble(); + double top_pt = resolution.y() * row[kTopInput].toDouble(); + double right_pt = resolution.x() * (1.0 - row[kRightInput].toDouble()); + double bottom_pt = resolution.y() * (1.0 - row[kBottomInput].toDouble()); + double center_x_pt = mid(left_pt, right_pt); + double center_y_pt = mid(top_pt, bottom_pt); - point_gizmo_[kGizmoScaleTopLeft]->SetPoint(QPointF(left_pt, top_pt)); - point_gizmo_[kGizmoScaleTopCenter]->SetPoint(QPointF(center_x_pt, top_pt)); - point_gizmo_[kGizmoScaleTopRight]->SetPoint(QPointF(right_pt, top_pt)); - point_gizmo_[kGizmoScaleBottomLeft]->SetPoint(QPointF(left_pt, bottom_pt)); - point_gizmo_[kGizmoScaleBottomCenter]->SetPoint(QPointF(center_x_pt, bottom_pt)); - point_gizmo_[kGizmoScaleBottomRight]->SetPoint(QPointF(right_pt, bottom_pt)); - point_gizmo_[kGizmoScaleCenterLeft]->SetPoint(QPointF(left_pt, center_y_pt)); - point_gizmo_[kGizmoScaleCenterRight]->SetPoint(QPointF(right_pt, center_y_pt)); + point_gizmo_[kGizmoScaleTopLeft]->SetPoint(QPointF(left_pt, top_pt)); + point_gizmo_[kGizmoScaleTopCenter]->SetPoint(QPointF(center_x_pt, top_pt)); + point_gizmo_[kGizmoScaleTopRight]->SetPoint(QPointF(right_pt, top_pt)); + point_gizmo_[kGizmoScaleBottomLeft]->SetPoint(QPointF(left_pt, bottom_pt)); + point_gizmo_[kGizmoScaleBottomCenter]->SetPoint(QPointF(center_x_pt, bottom_pt)); + point_gizmo_[kGizmoScaleBottomRight]->SetPoint(QPointF(right_pt, bottom_pt)); + point_gizmo_[kGizmoScaleCenterLeft]->SetPoint(QPointF(left_pt, center_y_pt)); + point_gizmo_[kGizmoScaleCenterRight]->SetPoint(QPointF(right_pt, center_y_pt)); - poly_gizmo_->SetPolygon(QRectF(left_pt, top_pt, right_pt - left_pt, bottom_pt - top_pt)); + poly_gizmo_->SetPolygon(QRectF(left_pt, top_pt, right_pt - left_pt, bottom_pt - top_pt)); + } } void CropDistortNode::GizmoDragMove(double x_diff, double y_diff, const Qt::KeyboardModifiers &modifiers) { DraggableGizmo *gizmo = static_cast(sender()); - QVector2D res = gizmo->GetGlobals().resolution(); + QVector2D res = temp_resolution_; x_diff /= res.x(); y_diff /= res.y(); diff --git a/app/node/distort/crop/cropdistortnode.h b/app/node/distort/crop/cropdistortnode.h index 1d6530152..ebbab1946 100644 --- a/app/node/distort/crop/cropdistortnode.h +++ b/app/node/distort/crop/cropdistortnode.h @@ -82,6 +82,7 @@ private: // Gizmo variables PointGizmo *point_gizmo_[kGizmoScaleCount]; PolygonGizmo *poly_gizmo_; + QVector2D temp_resolution_; }; diff --git a/app/node/distort/flip/flipdistortnode.cpp b/app/node/distort/flip/flipdistortnode.cpp index e2355ade7..6a1083099 100644 --- a/app/node/distort/flip/flipdistortnode.cpp +++ b/app/node/distort/flip/flipdistortnode.cpp @@ -77,18 +77,14 @@ ShaderCode FlipDistortNode::GetShaderCode(const ShaderRequest &request) const void FlipDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { + if (TexturePtr tex = value[kTextureInput].toTexture()) { // Only run shader if at least one of flip or flop are selected - if (job.Get(kHorizontalInput).toBool() || job.Get(kVerticalInput).toBool()) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (value[kHorizontalInput].toBool() || value[kVerticalInput].toBool()) { + table->Push(NodeValue::kTexture, tex->toJob(ShaderJob(value)), this); } else { // If we're not flipping or flopping just push the texture - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } diff --git a/app/node/distort/mask/mask.cpp b/app/node/distort/mask/mask.cpp index f19b8e961..dc1941b03 100644 --- a/app/node/distort/mask/mask.cpp +++ b/app/node/distort/mask/mask.cpp @@ -64,16 +64,19 @@ void MaskDistortNode::Retranslate() void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - NodeValue job(NodeValue::kTexture, GetGenerateJob(value), this); + TexturePtr texture = value[kBaseInput].toTexture(); + + VideoParams job_params = texture ? texture->params() : globals.vparams(); + NodeValue job(NodeValue::kTexture, Texture::Job(job_params, GetGenerateJob(value, job_params)), this); if (value[kInvertInput].toBool()) { ShaderJob invert; invert.SetShaderID(QStringLiteral("invert")); invert.Insert(QStringLiteral("tex_in"), job); - job.set_value(invert); + job.set_value(Texture::Job(job_params, invert)); } - if (value[kBaseInput].toTexture()) { + if (texture) { // Push as merge node ShaderJob merge; @@ -92,14 +95,14 @@ void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global feather.Insert(BlurFilterNode::kRepeatEdgePixelsInput, NodeValue(NodeValue::kBoolean, true, this)); feather.Insert(BlurFilterNode::kRadiusInput, NodeValue(NodeValue::kFloat, value[kFeatherInput].toDouble(), this)); feather.SetIterations(2, BlurFilterNode::kTextureInput); - feather.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + feather.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, texture ? texture->virtual_resolution() : globals.square_resolution(), this)); - merge.Insert(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, feather, this)); + merge.Insert(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, Texture::Job(job_params, feather), this)); } else { merge.Insert(QStringLiteral("tex_b"), job); } - table->Push(NodeValue::kTexture, merge, this); + table->Push(NodeValue::kTexture, Texture::Job(job_params, merge), this); } else { table->Push(job); } diff --git a/app/node/distort/ripple/rippledistortnode.cpp b/app/node/distort/ripple/rippledistortnode.cpp index bddb679d4..2e137ff3c 100644 --- a/app/node/distort/ripple/rippledistortnode.cpp +++ b/app/node/distort/ripple/rippledistortnode.cpp @@ -94,28 +94,26 @@ ShaderCode RippleDistortNode::GetShaderCode(const ShaderRequest &request) const void RippleDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { + if (TexturePtr tex = value[kTextureInput].toTexture()) { // Only run shader if at least one of flip or flop are selected - if (!qIsNull(job.Get(kIntensityInput).toDouble())) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (!qIsNull(value[kIntensityInput].toDouble())) { + ShaderJob job(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this)); + table->Push(NodeValue::kTexture, tex->toJob(job), this); } else { // If we're not flipping or flopping just push the texture - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } void RippleDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - QPointF half_res(globals.resolution_by_par().x()/2, globals.resolution_by_par().y()/2); - - gizmo_->SetPoint(half_res + row[kPositionInput].toVec2().toPointF()); + if (TexturePtr tex = row[kTextureInput].toTexture()) { + QPointF half_res(tex->virtual_resolution().x()/2, tex->virtual_resolution().y()/2); + gizmo_->SetPoint(half_res + row[kPositionInput].toVec2().toPointF()); + } } void RippleDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) diff --git a/app/node/distort/swirl/swirldistortnode.cpp b/app/node/distort/swirl/swirldistortnode.cpp index 658feb134..ddab58a60 100644 --- a/app/node/distort/swirl/swirldistortnode.cpp +++ b/app/node/distort/swirl/swirldistortnode.cpp @@ -89,26 +89,23 @@ ShaderCode SwirlDistortNode::GetShaderCode(const ShaderRequest &request) const void SwirlDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { + if (TexturePtr tex = value[kTextureInput].toTexture()) { // Only run shader if at least one of flip or flop are selected - if (!qIsNull(job.Get(kAngleInput).toDouble()) && !qIsNull(job.Get(kRadiusInput).toDouble())) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (!qIsNull(value[kAngleInput].toDouble()) && !qIsNull(value[kRadiusInput].toDouble())) { + ShaderJob job(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this)); + table->Push(NodeValue::kTexture, tex->toJob(job), this); } else { // If we're not flipping or flopping just push the texture - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } void SwirlDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - QPointF half_res(globals.resolution_by_par().x()/2, globals.resolution_by_par().y()/2); + QPointF half_res(globals.square_resolution().x()/2, globals.square_resolution().y()/2); gizmo_->SetPoint(half_res + row[kPositionInput].toVec2().toPointF()); } diff --git a/app/node/distort/tile/tiledistortnode.cpp b/app/node/distort/tile/tiledistortnode.cpp index acdb32aee..ec13a1ee4 100644 --- a/app/node/distort/tile/tiledistortnode.cpp +++ b/app/node/distort/tile/tiledistortnode.cpp @@ -110,47 +110,46 @@ ShaderCode TileDistortNode::GetShaderCode(const ShaderRequest &request) const void TileDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { + if (TexturePtr tex = value[kTextureInput].toTexture()) { // Only run shader if at least one of flip or flop are selected - if (!qFuzzyCompare(job.Get(kScaleInput).toDouble(), 1.0)) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (!qFuzzyCompare(value[kScaleInput].toDouble(), 1.0)) { + ShaderJob job(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this)); + table->Push(NodeValue::kTexture, tex->toJob(job), this); } else { // If we're not flipping or flopping just push the texture - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } void TileDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - QPointF res = globals.resolution_by_par().toPointF(); - QPointF pos = row[kPositionInput].toVec2().toPointF(); - qreal x = pos.x(); - qreal y = pos.y(); + if (TexturePtr tex = row[kTextureInput].toTexture()) { + QPointF res = tex->virtual_resolution().toPointF(); + QPointF pos = row[kPositionInput].toVec2().toPointF(); + qreal x = pos.x(); + qreal y = pos.y(); - Anchor a = static_cast(row[kAnchorInput].toInt()); - if (a == kTopLeft || a == kTopCenter || a == kTopRight) { - // Do nothing - } else if (a == kMiddleLeft || a == kMiddleCenter || a == kMiddleRight) { - y += res.y()/2; - } else if (a == kBottomLeft || a == kBottomCenter || a == kBottomRight) { - y += res.y(); - } - if (a == kTopLeft || a == kMiddleLeft || a == kBottomLeft) { - // Do nothing - } else if (a == kTopCenter || a == kMiddleCenter || a == kBottomCenter) { - x += res.x()/2; - } else if (a == kTopRight || a == kMiddleRight || a == kBottomRight) { - x += res.x(); - } + Anchor a = static_cast(row[kAnchorInput].toInt()); + if (a == kTopLeft || a == kTopCenter || a == kTopRight) { + // Do nothing + } else if (a == kMiddleLeft || a == kMiddleCenter || a == kMiddleRight) { + y += res.y()/2; + } else if (a == kBottomLeft || a == kBottomCenter || a == kBottomRight) { + y += res.y(); + } + if (a == kTopLeft || a == kMiddleLeft || a == kBottomLeft) { + // Do nothing + } else if (a == kTopCenter || a == kMiddleCenter || a == kBottomCenter) { + x += res.x()/2; + } else if (a == kTopRight || a == kMiddleRight || a == kBottomRight) { + x += res.x(); + } - gizmo_->SetPoint(QPointF(x, y)); + gizmo_->SetPoint(QPointF(x, y)); + } } void TileDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) diff --git a/app/node/distort/transform/transformdistortnode.cpp b/app/node/distort/transform/transformdistortnode.cpp index ab58b3378..b19934615 100644 --- a/app/node/distort/transform/transformdistortnode.cpp +++ b/app/node/distort/transform/transformdistortnode.cpp @@ -89,7 +89,7 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g // Pop texture NodeValue texture_meta = value[kTextureInput]; - QVariant job_to_push; + TexturePtr job_to_push = nullptr; // If we have a texture, generate a matrix and make it happen if (TexturePtr texture = texture_meta.toTexture()) { @@ -99,17 +99,18 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g if (!real_matrix.isIdentity()) { // The matrix will transform things ShaderJob job; - job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture), this)); + job.Insert(QStringLiteral("ove_maintex"), texture_meta); job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, real_matrix, this)); job.SetInterpolation(QStringLiteral("ove_maintex"), static_cast(value[kInterpolationInput].toInt())); - job_to_push = QVariant::fromValue(job); + // Use global resolution rather than texture resolution because this may result in a size change + job_to_push = Texture::Job(globals.vparams(), job); } } table->Push(NodeValue::kMatrix, QVariant::fromValue(generated_matrix), this); - if (job_to_push.isNull()) { + if (!job_to_push) { // Re-push whatever value we received table->Push(texture_meta); } else { @@ -142,7 +143,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou } gizmo_scale_uniform_ = row[kUniformScaleInput].toBool(); - gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().resolution()/2).toPointF(); + gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().nonsquare_resolution()/2).toPointF(); if (gizmo == point_gizmo_[kGizmoScaleTopLeft] || gizmo == point_gizmo_[kGizmoScaleTopRight] || gizmo == point_gizmo_[kGizmoScaleBottomLeft] || gizmo == point_gizmo_[kGizmoScaleBottomRight]) { @@ -177,7 +178,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou } else if (gizmo == rotation_gizmo_) { - gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().resolution()/2).toPointF(); + gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().nonsquare_resolution()/2).toPointF(); gizmo_start_angle_ = qAtan2(y - gizmo_anchor_pt_.y(), x - gizmo_anchor_pt_.x()); gizmo_last_angle_ = gizmo_start_angle_; gizmo_last_alt_angle_ = qAtan2(x - gizmo_anchor_pt_.x(), y - gizmo_anchor_pt_.y()); @@ -343,7 +344,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N } // Get the sequence resolution - const QVector2D &sequence_res = globals.resolution(); + const QVector2D &sequence_res = globals.nonsquare_resolution(); QVector2D sequence_half_res = sequence_res * 0.5; QPointF sequence_half_res_pt = sequence_half_res.toPointF(); @@ -418,7 +419,7 @@ QPointF TransformDistortNode::CreateScalePoint(double x, double y, const QPointF QMatrix4x4 TransformDistortNode::GenerateAutoScaledMatrix(const QMatrix4x4& generated_matrix, const NodeValueRow& value, const NodeGlobals &globals, const VideoParams& texture_params) const { - const QVector2D &sequence_res = globals.resolution(); + const QVector2D &sequence_res = globals.nonsquare_resolution(); QVector2D texture_res(texture_params.square_pixel_width(), texture_params.height()); AutoScaleType autoscale = static_cast(value[kAutoscaleInput].toInt()); diff --git a/app/node/distort/wave/wavedistortnode.cpp b/app/node/distort/wave/wavedistortnode.cpp index 6c49c1e0a..d3f948585 100644 --- a/app/node/distort/wave/wavedistortnode.cpp +++ b/app/node/distort/wave/wavedistortnode.cpp @@ -84,18 +84,14 @@ ShaderCode WaveDistortNode::GetShaderCode(const ShaderRequest &request) const void WaveDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { + if (TexturePtr texture = value[kTextureInput].toTexture()) { // Only run shader if at least one of flip or flop are selected - if (!qIsNull(job.Get(kIntensityInput).toDouble())) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (!qIsNull(value[kIntensityInput].toDouble())) { + table->Push(NodeValue::kTexture, Texture::Job(texture->params(), ShaderJob(value)), this); } else { // If we're not flipping or flopping just push the texture - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } diff --git a/app/node/effect/opacity/opacityeffect.cpp b/app/node/effect/opacity/opacityeffect.cpp index 6c60b36f1..cc0f2d2c0 100644 --- a/app/node/effect/opacity/opacityeffect.cpp +++ b/app/node/effect/opacity/opacityeffect.cpp @@ -45,17 +45,13 @@ ShaderCode OpacityEffect::GetShaderCode(const ShaderRequest &request) const void OpacityEffect::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { - if (!qFuzzyCompare(job.Get(kValueInput).toDouble(), 1.0)) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (TexturePtr tex = value[kTextureInput].toTexture()) { + if (!qFuzzyCompare(value[kValueInput].toDouble(), 1.0)) { + table->Push(NodeValue::kTexture, tex->toJob(ShaderJob(value)), this); } else { // 1.0 float is a no-op, so just push the texture - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 0ac4eb6d5..3955608b7 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -120,33 +120,28 @@ ShaderCode BlurFilterNode::GetShaderCode(const ShaderRequest &request) const void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { // If there's no texture, no need to run an operation - if (value[kTextureInput].toTexture()) { - - ShaderJob job; - - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - - Method method = static_cast(job.Get(kMethodInput).toInt()); + if (TexturePtr tex = value[kTextureInput].toTexture()) { + Method method = static_cast(value[kMethodInput].toInt()); bool can_push_job = true; + int iterations = 1; // Check if radius is > 0 - if (job.Get(kRadiusInput).toDouble() > 0.0) { + if (value[kRadiusInput].toDouble() > 0.0) { // Method-specific considerations switch (method) { case kBox: case kGaussian: { - bool horiz = job.Get(kHorizInput).toBool(); - bool vert = job.Get(kVertInput).toBool(); + bool horiz = value[kHorizInput].toBool(); + bool vert = value[kVertInput].toBool(); if (!horiz && !vert) { // Disable job if horiz and vert are unchecked can_push_job = false; } else if (horiz && vert) { // Set iteration count to 2 if we're blurring both horizontally and vertically - job.SetIterations(2, kTextureInput); + iterations = 2; } break; } @@ -159,10 +154,13 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals } if (can_push_job) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + ShaderJob job(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this)); + job.SetIterations(iterations, kTextureInput); + table->Push(NodeValue::kTexture, tex->toJob(job), this); } else { // If we're not performing the blur job, just push the texture - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } @@ -170,16 +168,18 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals void BlurFilterNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - if (row[kMethodInput].toInt() == kRadial) { - const QVector2D &sequence_res = globals.resolution(); - QVector2D sequence_half_res = sequence_res * 0.5; + if (TexturePtr tex = row[kTextureInput].toTexture()) { + if (row[kMethodInput].toInt() == kRadial) { + const QVector2D &sequence_res = tex->virtual_resolution(); + QVector2D sequence_half_res = sequence_res * 0.5; - radial_center_gizmo_->SetVisible(true); - radial_center_gizmo_->SetPoint(sequence_half_res.toPointF() + row[kRadialCenterInput].toVec2().toPointF()); + radial_center_gizmo_->SetVisible(true); + radial_center_gizmo_->SetPoint(sequence_half_res.toPointF() + row[kRadialCenterInput].toVec2().toPointF()); - SetInputProperty(kRadialCenterInput, QStringLiteral("offset"), sequence_half_res); - } else{ - radial_center_gizmo_->SetVisible(false); + SetInputProperty(kRadialCenterInput, QStringLiteral("offset"), sequence_half_res); + } else{ + radial_center_gizmo_->SetVisible(false); + } } } diff --git a/app/node/filter/dropshadow/dropshadowfilter.cpp b/app/node/filter/dropshadow/dropshadowfilter.cpp index a20b20f23..f8c60cdd5 100644 --- a/app/node/filter/dropshadow/dropshadowfilter.cpp +++ b/app/node/filter/dropshadow/dropshadowfilter.cpp @@ -78,20 +78,19 @@ ShaderCode DropShadowFilter::GetShaderCode(const ShaderRequest &request) const void DropShadowFilter::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - if (value[kTextureInput].toTexture()) { - ShaderJob job; + if (TexturePtr tex = value[kTextureInput].toTexture()) { + ShaderJob job(value); QString iterative = QStringLiteral("previous_iteration_in"); - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this)); job.Insert(iterative, value[kTextureInput]); if (!qIsNull(value[kSoftnessInput].toDouble())) { job.SetIterations(3, iterative); } - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, tex->toJob(job), this); } } diff --git a/app/node/filter/mosaic/mosaicfilternode.cpp b/app/node/filter/mosaic/mosaicfilternode.cpp index e5b5af8ca..9cb5f9af7 100644 --- a/app/node/filter/mosaic/mosaicfilternode.cpp +++ b/app/node/filter/mosaic/mosaicfilternode.cpp @@ -53,22 +53,18 @@ void MosaicFilterNode::Retranslate() void MosaicFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - - // Mipmapping makes this look weird, so we just use bilinear for finding the color of each block - job.SetInterpolation(kTextureInput, Texture::kLinear); - - if (job.Get(kTextureInput).toTexture()) { - TexturePtr texture = job.Get(kTextureInput).toTexture(); - + if (TexturePtr texture = value[kTextureInput].toTexture()) { if (texture - && job.Get(kHorizInput).toInt() != texture->width() - && job.Get(kVertInput).toInt() != texture->height()) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + && value[kHorizInput].toInt() != texture->width() + && value[kVertInput].toInt() != texture->height()) { + ShaderJob job(value); + + // Mipmapping makes this look weird, so we just use bilinear for finding the color of each block + job.SetInterpolation(kTextureInput, Texture::kLinear); + + table->Push(NodeValue::kTexture, texture->toJob(job), this); } else { - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index f8adc3f1f..389edb53b 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -86,17 +86,14 @@ void StrokeFilterNode::Retranslate() void StrokeFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - - if (job.Get(kTextureInput).toTexture()) { - if (job.Get(kRadiusInput).toDouble() > 0.0 - && job.Get(kOpacityInput).toDouble() > 0.0) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (TexturePtr tex = value[kTextureInput].toTexture()) { + if (value[kRadiusInput].toDouble() > 0.0 + && value[kOpacityInput].toDouble() > 0.0) { + ShaderJob job(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this)); + table->Push(NodeValue::kTexture, tex->toJob(job), this); } else { - table->Push(job.Get(kTextureInput)); + table->Push(value[kTextureInput]); } } } diff --git a/app/node/generator/noise/noise.cpp b/app/node/generator/noise/noise.cpp index 074a78278..94072db1d 100644 --- a/app/node/generator/noise/noise.cpp +++ b/app/node/generator/noise/noise.cpp @@ -80,11 +80,13 @@ ShaderCode NoiseGeneratorNode::GetShaderCode(const ShaderRequest &request) const void NoiseGeneratorNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; + ShaderJob job(value); job.Insert(value); job.Insert(QStringLiteral("time_in"), NodeValue(NodeValue::kFloat, globals.time().in().toDouble(), this)); - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + TexturePtr base = value[kBaseIn].toTexture(); + + table->Push(NodeValue::kTexture, Texture::Job(base ? base->params() : globals.vparams(), job), this); } } diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index ec65f8b7f..82a823556 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -87,12 +87,11 @@ void PolygonGenerator::Retranslate() SetInputName(kColorInput, tr("Color")); } -ShaderJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value) const +ShaderJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value, const VideoParams ¶ms) const { - GenerateJob job; - - job.Insert(value); - job.SetRequestedFormat(VideoParams::kFormatUnsigned8); + VideoParams p = params; + p.set_format(VideoParams::kFormatUnsigned8); + auto job = Texture::Job(p, GenerateJob(value)); // Conversion to RGB ShaderJob rgb; @@ -105,9 +104,7 @@ ShaderJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value) const void PolygonGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job = GetGenerateJob(value); - - PushMergableJob(value, QVariant::fromValue(job), table); + PushMergableJob(value, Texture::Job(globals.vparams(), GetGenerateJob(value, globals.vparams())), table); } void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) const @@ -169,7 +166,14 @@ void PolygonGenerator::ValidateGizmoVectorSize(QVector &vec, int new_sz) void PolygonGenerator::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - QPointF half_res(globals.resolution_by_par().x()/2, globals.resolution_by_par().y()/2); + QVector2D res; + if (TexturePtr tex = row[kBaseInput].toTexture()) { + res = tex->virtual_resolution(); + } else { + res = globals.square_resolution(); + } + + QPointF half_res = res.toPointF()/2; QVector points = row[kPointsInput].value< QVector >(); diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index dd7e5623b..e768c2230 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -60,7 +60,7 @@ public: static const QString kColorInput; protected: - ShaderJob GetGenerateJob(const NodeValueRow &value) const; + ShaderJob GetGenerateJob(const NodeValueRow &value, const VideoParams ¶ms) const; protected slots: virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) override; diff --git a/app/node/generator/shape/generatorwithmerge.cpp b/app/node/generator/shape/generatorwithmerge.cpp index 8174b5bf2..8622c1881 100644 --- a/app/node/generator/shape/generatorwithmerge.cpp +++ b/app/node/generator/shape/generatorwithmerge.cpp @@ -51,17 +51,17 @@ ShaderCode GeneratorWithMerge::GetShaderCode(const ShaderRequest &request) const return ShaderCode(); } -void GeneratorWithMerge::PushMergableJob(const NodeValueRow &value, const QVariant &job, NodeValueTable *table) const +void GeneratorWithMerge::PushMergableJob(const NodeValueRow &value, TexturePtr job, NodeValueTable *table) const { - if (value[kBaseInput].toTexture()) { + if (TexturePtr base = value[kBaseInput].toTexture()) { // Push as merge node ShaderJob merge; merge.SetShaderID(QStringLiteral("mrg")); merge.Insert(MergeNode::kBaseIn, value[kBaseInput]); - merge.Insert(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, job, this)); + merge.Insert(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, base->toJob(*job->job()), this)); - table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); + table->Push(NodeValue::kTexture, base->toJob(merge), this); } else { // Just push generate job table->Push(NodeValue::kTexture, job, this); diff --git a/app/node/generator/shape/generatorwithmerge.h b/app/node/generator/shape/generatorwithmerge.h index fb7d729f0..cc462a559 100644 --- a/app/node/generator/shape/generatorwithmerge.h +++ b/app/node/generator/shape/generatorwithmerge.h @@ -38,7 +38,7 @@ public: static const QString kBaseInput; protected: - void PushMergableJob(const NodeValueRow &value, const QVariant &job, NodeValueTable *table) const; + void PushMergableJob(const NodeValueRow &value, TexturePtr job, NodeValueTable *table) const; }; diff --git a/app/node/generator/shape/shapenode.cpp b/app/node/generator/shape/shapenode.cpp index d4808d768..b8f5a7132 100644 --- a/app/node/generator/shape/shapenode.cpp +++ b/app/node/generator/shape/shapenode.cpp @@ -77,13 +77,14 @@ ShaderCode ShapeNode::GetShaderCode(const ShaderRequest &request) const void ShapeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; + TexturePtr base = value[kBaseInput].toTexture(); - job.Insert(value); - job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + ShaderJob job(value); + + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, base ? base->virtual_resolution() : globals.square_resolution(), this)); job.SetShaderID(QStringLiteral("shape")); - PushMergableJob(value, QVariant::fromValue(job), table); + PushMergableJob(value, Texture::Job(base ? base->params() : globals.vparams(), job), table); } void ShapeNode::InputValueChangedEvent(const QString &input, int element) diff --git a/app/node/generator/shape/shapenodebase.cpp b/app/node/generator/shape/shapenodebase.cpp index 582725ec4..2a008526d 100644 --- a/app/node/generator/shape/shapenodebase.cpp +++ b/app/node/generator/shape/shapenodebase.cpp @@ -77,7 +77,7 @@ void ShapeNodeBase::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlob { // Use offsets to make the appearance of values that start in the top left, even though we // really anchor around the center - QVector2D center_pt = globals.resolution() * 0.5; + QVector2D center_pt = globals.square_resolution() * 0.5; SetInputProperty(kPositionInput, QStringLiteral("offset"), center_pt); QVector2D pos = row[kPositionInput].toVec2(); @@ -137,7 +137,7 @@ void ShapeNodeBase::GizmoDragMove(double x, double y, const Qt::KeyboardModifier QVector2D gizmo_sz_start(w_drag.GetStartValue().toDouble(), h_drag.GetStartValue().toDouble()); QVector2D gizmo_pos_start(x_drag.GetStartValue().toDouble(), y_drag.GetStartValue().toDouble()); - QVector2D gizmo_half_res = gizmo->GetGlobals().resolution()/2; + QVector2D gizmo_half_res = gizmo->GetGlobals().square_resolution()/2; QVector2D adjusted_pt(x, y); QVector2D new_size; QVector2D new_pos; diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index a99a7f370..d485a48f9 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -63,9 +63,7 @@ void SolidGenerator::Retranslate() void SolidGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - job.Insert(value); - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, Texture::Job(globals.vparams(), ShaderJob(value)), this); } ShaderCode SolidGenerator::GetShaderCode(const ShaderRequest &request) const diff --git a/app/node/generator/text/textv1.cpp b/app/node/generator/text/textv1.cpp index 93d36737f..68c3a5e7d 100644 --- a/app/node/generator/text/textv1.cpp +++ b/app/node/generator/text/textv1.cpp @@ -92,11 +92,8 @@ void TextGeneratorV1::Retranslate() void TextGeneratorV1::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - GenerateJob job; - job.Insert(value); - - if (!job.Get(kTextInput).toString().isEmpty()) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (!value[kTextInput].toString().isEmpty()) { + table->Push(NodeValue::kTexture, Texture::Job(globals.vparams(), GenerateJob(value)), this); } } diff --git a/app/node/generator/text/textv2.cpp b/app/node/generator/text/textv2.cpp index e3032e55a..7cf82cd83 100644 --- a/app/node/generator/text/textv2.cpp +++ b/app/node/generator/text/textv2.cpp @@ -94,12 +94,11 @@ void TextGeneratorV2::Retranslate() void TextGeneratorV2::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - GenerateJob job; - job.Insert(value); - job.SetRequestedFormat(VideoParams::kFormatFloat32); - - if (!job.Get(kTextInput).toString().isEmpty()) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (!value[kTextInput].toString().isEmpty()) { + GenerateJob job(value); + auto text_params = globals.vparams(); + text_params.set_format(VideoParams::kFormatFloat32); + table->Push(NodeValue::kTexture, Texture::Job(text_params, job), this); } } diff --git a/app/node/generator/text/textv3.cpp b/app/node/generator/text/textv3.cpp index a723e67aa..afe900778 100644 --- a/app/node/generator/text/textv3.cpp +++ b/app/node/generator/text/textv3.cpp @@ -98,9 +98,7 @@ void TextGeneratorV3::Retranslate() void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - GenerateJob job; - job.Insert(value); - job.SetRequestedFormat(VideoParams::kFormatUnsigned8); + QString text = value[kTextInput].toString(); if (value[kUseArgsInput].toBool()) { auto args = value[kArgsInput].toArray(); @@ -111,17 +109,21 @@ void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &global list.append(args[i].toString()); } - NodeValue v = job.Get(kTextInput); - v.set_value(FormatString(v.toString(), list)); - job.Insert(kTextInput, v); + text = FormatString(text, list); } } - // FIXME: Provide user override for this - job.SetColorspace(project()->color_manager()->GetDefaultInputColorSpace()); + if (!text.isEmpty()) { + TexturePtr base = value[kTextInput].toTexture(); - if (!job.Get(kTextInput).toString().isEmpty()) { - PushMergableJob(value, QVariant::fromValue(job), table); + VideoParams text_params = base ? base->params() : globals.vparams(); + text_params.set_format(VideoParams::kFormatUnsigned8); + text_params.set_colorspace(project()->color_manager()->GetDefaultInputColorSpace()); + + GenerateJob job(value); + job.Insert(kTextInput, NodeValue(NodeValue::kText, text)); + + PushMergableJob(value, Texture::Job(text_params, job), table); } else if (value[kBaseInput].toTexture()) { table->Push(value[kBaseInput]); } diff --git a/app/node/globals.h b/app/node/globals.h index be1d11d6f..4db941be9 100644 --- a/app/node/globals.h +++ b/app/node/globals.h @@ -39,9 +39,9 @@ public: { } - QVector2D resolution() const { return video_params_.resolution(); } - QVector2D resolution_by_par() const { return video_params_.square_resolution(); } - const VideoParams &video_params() const { return video_params_; } + QVector2D square_resolution() const { return video_params_.square_resolution(); } + QVector2D nonsquare_resolution() const { return video_params_.resolution(); } + const VideoParams &vparams() const { return video_params_; } const TimeRange &time() const { return time_; } private: diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 70babc998..f78d4db9a 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -128,16 +128,17 @@ void ChromaKeyNode::GenerateProcessor() void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - if (value[kTextureInput].toTexture() && processor()) { - ColorTransformJob job; + if (TexturePtr tex = value[kTextureInput].toTexture()) { + if (processor()) { + ColorTransformJob job(value); - job.Insert(value); - job.SetColorProcessor(processor()); - job.SetInputTexture(value[kTextureInput].toTexture()); - job.SetNeedsCustomShader(this); - job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65")); + job.SetColorProcessor(processor()); + job.SetInputTexture(value[kTextureInput]); + job.SetNeedsCustomShader(this); + job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65")); - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, tex->toJob(job), this); + } } } diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index 7ee988d66..8627efdda 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -93,12 +93,11 @@ ShaderCode ColorDifferenceKeyNode::GetShaderCode(const ShaderRequest &request) c void ColorDifferenceKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - job.Insert(value); - // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (TexturePtr tex = value[kTextureInput].toTexture()) { + ShaderJob job; + job.Insert(value); + table->Push(NodeValue::kTexture, tex->toJob(job), this); } } diff --git a/app/node/keying/despill/despill.cpp b/app/node/keying/despill/despill.cpp index 3f8e22723..8b91d3dfd 100644 --- a/app/node/keying/despill/despill.cpp +++ b/app/node/keying/despill/despill.cpp @@ -91,8 +91,8 @@ void DespillNode::Value(const NodeValueRow &value, const NodeGlobals &globals, N NodeValue(NodeValue::kVec3, QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]))); // If there's no texture, no need to run an operation - if (job.Get(kTextureInput).toTexture()) { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + if (TexturePtr tex = job.Get(kTextureInput).toTexture()) { + table->Push(NodeValue::kTexture, tex->toJob(job), this); } } diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index 7f3c12440..4ed0ea5f6 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -358,7 +358,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt } } else if (pairing == kPairTextureMatrix) { // Only allow matrix multiplication - const QVector2D &sequence_res = globals.resolution(); + const QVector2D &sequence_res = globals.nonsquare_resolution(); QVector2D texture_res(texture->params().width() * texture->pixel_aspect_ratio().toDouble(), texture->params().height()); QMatrix4x4 adjusted_matrix = TransformDistortNode::AdjustMatrixByResolutions(number_val.toMatrix(), @@ -380,7 +380,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt output->Push(texture_val); } else { // Push shader job - output->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + output->Push(NodeValue::kTexture, Texture::Job(globals.vparams(), job), this); } break; } diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index acf271869..2285a6c32 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -76,21 +76,19 @@ ShaderCode MergeNode::GetShaderCode(const ShaderRequest &request) const void MergeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - ShaderJob job; - job.Insert(value); - TexturePtr base_tex = job.Get(kBaseIn).toTexture(); - TexturePtr blend_tex = job.Get(kBlendIn).toTexture(); + TexturePtr base_tex = value[kBaseIn].toTexture(); + TexturePtr blend_tex = value[kBlendIn].toTexture(); if (base_tex || blend_tex) { if (!base_tex || (blend_tex && blend_tex->channel_count() < VideoParams::kRGBAChannelCount)) { // We only have a blend texture or the blend texture is RGB only, no need to alpha over - table->Push(job.Get(kBlendIn)); + table->Push(value[kBlendIn]); } else if (!blend_tex) { // We only have a base texture, no need to alpha over - table->Push(job.Get(kBaseIn)); + table->Push(value[kBaseIn]); } else { - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, base_tex->toJob(ShaderJob(value)), this); } } } diff --git a/app/node/project/footage/footage.cpp b/app/node/project/footage/footage.cpp index cbc600779..307ce247b 100644 --- a/app/node/project/footage/footage.cpp +++ b/app/node/project/footage/footage.cpp @@ -267,26 +267,31 @@ void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV Track::Reference ref = GetReferenceFromRealIndex(i); FootageJob job(globals.time(), decoder_, filename(), ref.type(), GetLength()); - NodeValue::Type type; - if (ref.type() == Track::kVideo) { VideoParams vp = GetVideoParams(ref.index()); // Ensure the colorspace is valid and not empty vp.set_colorspace(GetColorspaceToUse(vp)); + // Adjust footage job's divider + if (globals.vparams().divider() > 1) { + // Use a divider appropriate for this target resolution + vp.set_divider(VideoParams::GetDividerForTargetResolution(vp.width(), vp.height(), globals.vparams().effective_width(), globals.vparams().effective_height())); + } else { + // Render everything at full res + vp.set_divider(1); + } + job.set_video_params(vp); - type = NodeValue::kTexture; + table->Push(NodeValue::kTexture, Texture::Job(vp, job), this, ref.ToString()); } else { AudioParams ap = GetAudioParams(ref.index()); job.set_audio_params(ap); job.set_cache_path(project()->cache_path()); - type = NodeValue::kSamples; + table->Push(NodeValue::kSamples, QVariant::fromValue(job), this, ref.ToString()); } - - table->Push(type, QVariant::fromValue(job), this, ref.ToString()); } } } diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 6b1dae1cf..028028f46 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -61,7 +61,7 @@ NodeValueRow NodeTraverser::GenerateRow(NodeValueDatabase *database, const Node row.insert(it.key(), value); } - PreProcessRow(row); + //PreProcessRow(row); return row; } @@ -110,13 +110,15 @@ NodeValue NodeTraverser::GenerateRowValueElement(const Node *node, const QString NodeValue value = table->TakeAt(value_index); if (value.type() == NodeValue::kTexture && UseCache()) { - QMutexLocker locker(node->video_frame_cache()->mutex()); + if (TexturePtr tex = value.toTexture()) { + QMutexLocker locker(node->video_frame_cache()->mutex()); - node->video_frame_cache()->LoadState(); + node->video_frame_cache()->LoadState(); - QString cache = node->video_frame_cache()->GetValidCacheFilename(time.in()); - if (!cache.isEmpty()) { - value.set_value(CacheJob(cache, value.data())); + QString cache = node->video_frame_cache()->GetValidCacheFilename(time.in()); + if (!cache.isEmpty()) { + value.set_value(tex->toJob(CacheJob(cache, value))); + } } } @@ -174,25 +176,6 @@ NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams ¶ms, const Time return NodeGlobals(params, time); } -int NodeTraverser::GetChannelCountFromJob(const GenerateJob &job) -{ - return VideoParams::kRGBAChannelCount; -} - -TexturePtr NodeTraverser::GetMainTextureFromJob(const GenerateJob &job) -{ - // FIXME: Should probably take Node::GetEffectInput into account here - for (auto it=job.GetValues().cbegin(); it!=job.GetValues().cend(); it++) { - if (it.value().type() == NodeValue::kTexture) { - if (TexturePtr t = it.value().toTexture()) { - return t; - } - } - } - - return nullptr; -} - NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& input, const TimeRange& range) { // If input is connected, retrieve value directly @@ -277,7 +260,13 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang return GenerateBlockTable(track, range); } - // FIXME: Cache certain values here if we've already processed them before + // Use table cache to skip processing where available + if (value_cache_.contains(n)) { + QHash &node_value_map = value_cache_[n]; + if (node_value_map.contains(range)) { + return node_value_map.value(range); + } + } // Generate row for node NodeValueDatabase database = GenerateDatabase(n, range); @@ -291,11 +280,13 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang is_enabled = database[Node::kEnabledInput].Get(NodeValue::kBoolean).toBool(); } + NodeValueTable table; + if (is_enabled) { NodeValueRow row = GenerateRow(&database, n, range); // Generate output table - NodeValueTable table = database.Merge(); + table = database.Merge(); // By this point, the node should have all the inputs it needs to render correctly NodeGlobals globals = GenerateGlobals(video_params_, range); @@ -316,8 +307,6 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang transform_now_ = next_node; } } - - return table; } else { // If this node has an effect input, ensure that is pushed last NodeValueTable primary; @@ -325,10 +314,13 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang primary = database.Take(n->GetEffectInputID()); } - NodeValueTable m = database.Merge(); - m.Push(primary); - return m; + table = database.Merge(); + table.Push(primary); } + + value_cache_[n][range] = table; + + return table; } NodeValueTable NodeTraverser::GenerateBlockTable(const Track *track, const TimeRange &range) @@ -347,7 +339,7 @@ NodeValueTable NodeTraverser::GenerateBlockTable(const Track *track, const TimeR return table; } -TexturePtr NodeTraverser::ProcessVideoCacheJob(const CacheJob &val) +TexturePtr NodeTraverser::ProcessVideoCacheJob(const CacheJob *val) { return nullptr; } @@ -359,151 +351,127 @@ QVector2D NodeTraverser::GenerateResolution() const void NodeTraverser::ResolveJobs(NodeValue &val) { - if (val.type() == NodeValue::kTexture || val.type() == NodeValue::kSamples) { - if (val.canConvert()) { - CacheJob job = val.value(); - TexturePtr tex = ProcessVideoCacheJob(job); - if (tex) { - val.set_value(tex); - } else { - val.set_value(job.GetFallback()); + if (val.type() == NodeValue::kTexture) { + + if (TexturePtr job_tex = val.toTexture()) { + if (AcceleratedJob *base_job = job_tex->job()) { + + if (resolved_texture_cache_.contains(job_tex.get())) { + val.set_value(resolved_texture_cache_.value(job_tex.get())); + } else { + // Resolve any sub-jobs + for (auto it=base_job->GetValues().begin(); it!=base_job->GetValues().end(); it++) { + // Jobs will almost always be submitted with one of these types + NodeValue &subval = it.value(); + ResolveJobs(subval); + } + + if (CacheJob *cj = dynamic_cast(base_job)) { + TexturePtr tex = ProcessVideoCacheJob(cj); + if (tex) { + val.set_value(tex); + } else { + val.set_value(cj->GetFallback()); + } + + } else if (ColorTransformJob *ctj = dynamic_cast(base_job)) { + + VideoParams ctj_params = job_tex->params(); + + ctj_params.set_format(GetCacheVideoParams().format()); + + TexturePtr dest = CreateTexture(ctj_params); + + // Resolve input texture + NodeValue v = ctj->GetInputTexture(); + ResolveJobs(v); + ctj->SetInputTexture(v); + + ProcessColorTransform(dest, val.source(), ctj); + + val.set_value(dest); + + } else if (ShaderJob *sj = dynamic_cast(base_job)) { + + VideoParams tex_params = job_tex->params(); + + TexturePtr tex = CreateTexture(tex_params); + + ProcessShader(tex, val.source(), sj); + + val.set_value(tex); + + } else if (GenerateJob *gj = dynamic_cast(base_job)) { + + VideoParams tex_params = job_tex->params(); + + TexturePtr tex = CreateTexture(tex_params); + + ProcessFrameGeneration(tex, val.source(), gj); + + // Convert to reference space + const QString &colorspace = tex_params.colorspace(); + if (!colorspace.isEmpty()) { + // Set format to primary format + tex_params.set_format(GetCacheVideoParams().format()); + + TexturePtr dest = CreateTexture(tex_params); + + ConvertToReferenceSpace(dest, tex, colorspace); + + tex = dest; + } + + val.set_value(tex); + + } else if (FootageJob *fj = dynamic_cast(base_job)) { + + rational footage_time = Footage::AdjustTimeByLoopMode(fj->time().in(), loop_mode_, fj->length(), fj->video_params().video_type(), fj->video_params().frame_rate_as_time_base()); + + TexturePtr tex; + + if (footage_time.isNaN()) { + // Push dummy texture + tex = CreateDummyTexture(fj->video_params()); + } else { + VideoParams managed_params = fj->video_params(); + managed_params.set_format(GetCacheVideoParams().format()); + + tex = CreateTexture(managed_params); + ProcessVideoFootage(tex, fj, footage_time); + } + + val.set_value(tex); + + } + + // Cache resolved value + resolved_texture_cache_.insert(job_tex.get(), val.toTexture()); + } } } - if (val.canConvert()) { + } else if (val.type() == NodeValue::kSamples) { - ShaderJob job = val.value(); - - PreProcessRow(job.GetValues()); - - VideoParams tex_params = GetCacheVideoParams(); - tex_params.set_channel_count(GetChannelCountFromJob(job)); - - if (!job.GetWillChangeImageSize()) { - if (TexturePtr texture = GetMainTextureFromJob(job)) { - tex_params.set_width(texture->params().width()); - tex_params.set_height(texture->params().height()); - tex_params.set_divider(texture->params().divider()); - } - } - - TexturePtr tex = CreateTexture(tex_params); - - ProcessShader(tex, val.source(), job); - - val.set_value(tex); - - } else if (val.canConvert()) { - - GenerateJob job = val.value(); - - VideoParams tex_params = GetCacheVideoParams(); - tex_params.set_channel_count(GetChannelCountFromJob(job)); - - VideoParams upload_params = tex_params; - if (job.GetRequestedFormat() != VideoParams::kFormatInvalid) { - upload_params.set_format(job.GetRequestedFormat()); - } - - TexturePtr tex = CreateTexture(upload_params); - - PreProcessRow(job.GetValues()); - ProcessFrameGeneration(tex, val.source(), job); - - if (!job.GetColorspace().isEmpty()) { - // Convert to reference space - TexturePtr dest = CreateTexture(tex_params); - - ConvertToReferenceSpace(dest, tex, job.GetColorspace()); - - tex = dest; - } - - val.set_value(tex); - - } else if (val.canConvert()) { - - ColorTransformJob job = val.value(); - - VideoParams src_params = job.GetInputTexture()->params(); - src_params.set_channel_count(GetChannelCountFromJob(job)); - - TexturePtr dest = CreateTexture(src_params); - - ProcessColorTransform(dest, val.source(), job); - - val.set_value(dest); - - } else if (val.canConvert()) { - - FootageJob job = val.value(); - - if (job.type() == Track::kVideo) { - - rational footage_time = Footage::AdjustTimeByLoopMode(job.time().in(), loop_mode_, job.length(), job.video_params().video_type(), job.video_params().frame_rate_as_time_base()); - - TexturePtr tex; - - // Adjust footage job's divider - VideoParams render_params = GetCacheVideoParams(); - VideoParams job_params = job.video_params(); - - if (render_params.divider() > 1) { - // Use a divider appropriate for this target resolution - job_params.set_divider(VideoParams::GetDividerForTargetResolution(job_params.width(), job_params.height(), render_params.effective_width(), render_params.effective_height())); - } else { - // Render everything at full res - job_params.set_divider(1); - } - - job.set_video_params(job_params); - - if (footage_time.isNaN()) { - // Push dummy texture - tex = CreateDummyTexture(job.video_params()); - } else { - VideoParams managed_params = job.video_params(); - managed_params.set_format(GetCacheVideoParams().format()); - - tex = CreateTexture(managed_params); - ProcessVideoFootage(tex, job, footage_time); - } - - val.set_value(tex); - - } else if (job.type() == Track::kAudio) { - - SampleBuffer buffer = CreateSampleBuffer(GetCacheAudioParams(), job.time().length()); - ProcessAudioFootage(buffer, job, job.time()); - val.set_value(buffer); - - } - - } else if (val.canConvert()) { + if (val.canConvert()) { SampleJob job = val.value(); SampleBuffer output_buffer = CreateSampleBuffer(job.samples().audio_params(), job.samples().sample_count()); ProcessSamples(output_buffer, val.source(), job.time(), job); val.set_value(QVariant::fromValue(output_buffer)); + } else if (val.canConvert()) { + + FootageJob job = val.value(); + SampleBuffer buffer = CreateSampleBuffer(GetCacheAudioParams(), job.time().length()); + ProcessAudioFootage(buffer, &job, job.time()); + val.set_value(buffer); + } } } -void NodeTraverser::PreProcessRow(NodeValueRow &row) -{ - QByteArray cached_node_hash; - - // Resolve any jobs - for (auto it=row.begin(); it!=row.end(); it++) { - // Jobs will almost always be submitted with one of these types - NodeValue &val = it.value(); - - ResolveJobs(val); - } -} - TexturePtr NodeTraverser::CreateDummyTexture(const VideoParams &p) { return std::make_shared(p); diff --git a/app/node/traverser.h b/app/node/traverser.h index 1defd0168..4ecf3982a 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -80,30 +80,26 @@ public: audio_params_ = params; } - static int GetChannelCountFromJob(const GenerateJob& job); - - static TexturePtr GetMainTextureFromJob(const GenerateJob& job); - protected: NodeValueTable ProcessInput(const Node *node, const QString &input, const TimeRange &range); virtual NodeValueTable GenerateBlockTable(const Track *track, const TimeRange& range); - virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time){} + virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob *stream, const rational &input_time){} - virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time){} + virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob *stream, const TimeRange &input_time){} - virtual void ProcessShader(TexturePtr destination, const Node *node, const ShaderJob& job){} + virtual void ProcessShader(TexturePtr destination, const Node *node, const ShaderJob *job){} - virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job){} + virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob *job){} virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job){} - virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job){} + virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob *job){} virtual void ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs){} - virtual TexturePtr ProcessVideoCacheJob(const CacheJob &val); + virtual TexturePtr ProcessVideoCacheJob(const CacheJob *val); virtual TexturePtr CreateTexture(const VideoParams &p) { @@ -152,8 +148,6 @@ protected: virtual bool UseCache() const { return false; } private: - void PreProcessRow(NodeValueRow &row); - TexturePtr CreateDummyTexture(const VideoParams &p); VideoParams video_params_; @@ -170,6 +164,9 @@ private: Decoder::LoopMode loop_mode_; + QHash > value_cache_; + QHash resolved_texture_cache_; + }; } diff --git a/app/node/value.h b/app/node/value.h index e4d373ae7..e90381069 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -264,6 +264,11 @@ public: return type_ == rhs.type_ && tag_ == rhs.tag_ && data_ == rhs.data_; } + operator bool() const + { + return !data_.isNull(); + } + static QString GetPrettyDataTypeName(Type type); static QString GetDataTypeName(Type type); diff --git a/app/render/job/acceleratedjob.h b/app/render/job/acceleratedjob.h index 9468a9a74..7373d52c1 100644 --- a/app/render/job/acceleratedjob.h +++ b/app/render/job/acceleratedjob.h @@ -26,10 +26,13 @@ namespace olive { -class AcceleratedJob { +class AcceleratedJob +{ public: AcceleratedJob() = default; + virtual ~AcceleratedJob(){} + NodeValue Get(const QString& input) const { return value_map_.value(input); diff --git a/app/render/job/cachejob.h b/app/render/job/cachejob.h index 67c6c36b9..4d7800ce1 100644 --- a/app/render/job/cachejob.h +++ b/app/render/job/cachejob.h @@ -24,13 +24,16 @@ #include #include +#include "node/value.h" +#include "render/job/acceleratedjob.h" + namespace olive { -class CacheJob +class CacheJob : public AcceleratedJob { public: CacheJob() = default; - CacheJob(const QString &filename, const QVariant &fallback = QVariant()) + CacheJob(const QString &filename, const NodeValue &fallback = NodeValue()) { filename_ = filename; } @@ -38,18 +41,16 @@ public: const QString &GetFilename() const { return filename_; } void SetFilename(const QString &s) { filename_ = s; } - const QVariant &GetFallback() const { return fallback_; } - void SetFallback(const QVariant &val) { fallback_ = val; } + const NodeValue &GetFallback() const { return fallback_; } + void SetFallback(const NodeValue &val) { fallback_ = val; } private: QString filename_; - QVariant fallback_; + NodeValue fallback_; }; } -Q_DECLARE_METATYPE(olive::CacheJob) - #endif // CACHEJOB_H diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index da7846d2c..15951b22e 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -24,7 +24,7 @@ #include #include -#include "render/job/generatejob.h" +#include "acceleratedjob.h" #include "render/alphaassoc.h" #include "render/colorprocessor.h" #include "render/texture.h" @@ -33,18 +33,23 @@ namespace olive { class Node; -class ColorTransformJob : public GenerateJob +class ColorTransformJob : public AcceleratedJob { public: ColorTransformJob() { processor_ = nullptr; - input_texture_ = nullptr; custom_shader_src_ = nullptr; input_alpha_association_ = kAlphaNone; clear_destination_ = true; } + ColorTransformJob(const NodeValueRow &row) : + ColorTransformJob() + { + Insert(row); + } + QString id() const { if (id_.isEmpty()) { @@ -56,8 +61,13 @@ public: void SetOverrideID(const QString &id) { id_ = id; } - TexturePtr GetInputTexture() const { return input_texture_; } - void SetInputTexture(TexturePtr tex) { input_texture_ = tex; } + const NodeValue &GetInputTexture() const { return input_texture_; } + void SetInputTexture(const NodeValue &tex) { input_texture_ = tex; } + void SetInputTexture(TexturePtr tex) + { + Q_ASSERT(!tex->IsDummy()); + input_texture_ = NodeValue(NodeValue::kTexture, tex); + } ColorProcessorPtr GetColorProcessor() const { return processor_; } void SetColorProcessor(ColorProcessorPtr p) { processor_ = p; } @@ -89,7 +99,7 @@ private: ColorProcessorPtr processor_; QString id_; - TexturePtr input_texture_; + NodeValue input_texture_; const Node *custom_shader_src_; QString custom_shader_id_; @@ -108,6 +118,4 @@ private: } -Q_DECLARE_METATYPE(olive::ColorTransformJob) - #endif // COLORTRANSFORMJOB_H diff --git a/app/render/job/footagejob.h b/app/render/job/footagejob.h index 3684fa999..dcafee554 100644 --- a/app/render/job/footagejob.h +++ b/app/render/job/footagejob.h @@ -25,7 +25,7 @@ namespace olive { -class FootageJob +class FootageJob : public AcceleratedJob { public: FootageJob() : diff --git a/app/render/job/generatejob.h b/app/render/job/generatejob.h index 0109e1195..ed13998ef 100644 --- a/app/render/job/generatejob.h +++ b/app/render/job/generatejob.h @@ -22,33 +22,22 @@ #define GENERATEJOB_H #include "acceleratedjob.h" -#include "render/videoparams.h" +#include "codec/frame.h" namespace olive { -class GenerateJob : public AcceleratedJob { +class GenerateJob : public AcceleratedJob +{ public: - GenerateJob() + GenerateJob() = default; + GenerateJob(const NodeValueRow &row) : + GenerateJob() { - requested_format_ = VideoParams::kFormatInvalid; + Insert(row); } - VideoParams::Format GetRequestedFormat() const { return requested_format_; } - - void SetRequestedFormat(VideoParams::Format f) { requested_format_ = f; } - - const QString &GetColorspace() const { return colorspace_; } - void SetColorspace(const QString &s) { colorspace_ = s; } - -private: - VideoParams::Format requested_format_; - - QString colorspace_; - }; } -Q_DECLARE_METATYPE(olive::GenerateJob) - #endif // GENERATEJOB_H diff --git a/app/render/job/samplejob.h b/app/render/job/samplejob.h index 03bc00e6e..f5602a8ba 100644 --- a/app/render/job/samplejob.h +++ b/app/render/job/samplejob.h @@ -27,7 +27,8 @@ namespace olive { -class SampleJob : public AcceleratedJob { +class SampleJob : public AcceleratedJob +{ public: SampleJob() { diff --git a/app/render/job/shaderjob.h b/app/render/job/shaderjob.h index 0669e0c42..4cba60e7a 100644 --- a/app/render/job/shaderjob.h +++ b/app/render/job/shaderjob.h @@ -24,19 +24,24 @@ #include #include -#include "generatejob.h" -#include "render/colorprocessor.h" +#include "acceleratedjob.h" #include "render/texture.h" namespace olive { -class ShaderJob : public GenerateJob { +class ShaderJob : public AcceleratedJob +{ public: ShaderJob() { iterations_ = 1; iterative_input_ = nullptr; - will_change_image_size_ = true; + } + + ShaderJob(const NodeValueRow &row) : + ShaderJob() + { + Insert(row); } const QString& GetShaderID() const @@ -100,9 +105,6 @@ public: return vertex_overrides_; } - bool GetWillChangeImageSize() const { return will_change_image_size_; } - void SetWillChangeImageSize(bool e) { will_change_image_size_ = e; } - private: QString shader_id_; @@ -114,12 +116,8 @@ private: QVector vertex_overrides_; - bool will_change_image_size_; - }; } -Q_DECLARE_METATYPE(olive::ShaderJob) - #endif // SHADERJOB_H diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index 8c6f2a703..2cb608783 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -415,6 +415,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video // This variable is used in the shader, let's set it const NodeValue& value = it.value(); + // Arrays are not currently supported in this system if (value.array()) { continue; } diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 9aa24dbd1..a5a3aaedb 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -292,7 +292,7 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *des } ShaderJob job; - job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(color_job.GetInputTexture()))); + job.Insert(QStringLiteral("ove_maintex"), color_job.GetInputTexture()); job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix())); job.Insert(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, color_job.GetCropMatrix().inverted())); job.Insert(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, int(color_job.GetInputAlphaAssociation()))); diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index fc4f26c02..4da2ea852 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -54,8 +54,13 @@ TexturePtr RenderProcessor::GenerateTexture(const rational &time, const rational NodeValue tex_val = table.Get(NodeValue::kTexture); + QElapsedTimer t; + t.restart(); + ResolveJobs(tex_val); + qDebug() << "Frame took" << t.elapsed(); + return tex_val.toTexture(); } @@ -406,7 +411,7 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim } } -void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time) +void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJob *stream, const rational &input_time) { if (ticket_->property("type").value() != RenderManager::kTypeVideo) { // Video cannot contribute to audio, so we do nothing here @@ -416,7 +421,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ // Check the still frame cache. On large frames such as high resolution still images, uploading // and color managing them for every frame is a waste of time, so we implement a small cache here // to optimize such a situation - VideoParams stream_data = stream.video_params(); + VideoParams stream_data = stream->video_params(); ColorManager* color_manager = Node::ValueToPtr(ticket_->property("colormanager")); @@ -427,9 +432,9 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ qWarning() << "HAVEN'T GOTTEN DEFAULT INPUT COLORSPACE"; } - Decoder::CodecStream default_codec_stream(stream.filename(), stream_data.stream_index(), GetCurrentBlock()); + Decoder::CodecStream default_codec_stream(stream->filename(), stream_data.stream_index(), GetCurrentBlock()); - QString decoder_id = stream.decoder(); + QString decoder_id = stream->decoder(); DecoderPtr decoder = nullptr; @@ -447,7 +452,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ QString frame_filename; int64_t frame_number = stream_data.get_time_in_timebase_units(input_time); - frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number); + frame_filename = Decoder::TransformImageSequenceFileName(stream->filename(), frame_number); // Decoder will close automatically since it's a stream_ptr decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index(), GetCurrentBlock())); @@ -458,11 +463,11 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ if (decoder && render_ctx_) { Decoder::RetrieveVideoParams p; - p.divider = stream.video_params().divider(); + p.divider = stream->video_params().divider(); p.maximum_format = destination->format(); if (!IsCancelled()) { - VideoParams tex_params = stream.video_params(); + VideoParams tex_params = stream->video_params(); if (tex_params.is_valid()) { TexturePtr unmanaged_texture; @@ -503,16 +508,16 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ } } -void RenderProcessor::ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time) +void RenderProcessor::ProcessAudioFootage(SampleBuffer &destination, const FootageJob *stream, const TimeRange &input_time) { - DecoderPtr decoder = ResolveDecoderFromInput(stream.decoder(), Decoder::CodecStream(stream.filename(), stream.audio_params().stream_index(), nullptr)); + DecoderPtr decoder = ResolveDecoderFromInput(stream->decoder(), Decoder::CodecStream(stream->filename(), stream->audio_params().stream_index(), nullptr)); if (decoder) { const AudioParams& audio_params = GetCacheAudioParams(); Decoder::RetrieveAudioStatus status = decoder->RetrieveAudio(destination, input_time, audio_params, - stream.cache_path(), + stream->cache_path(), loop_mode(), static_cast(ticket_->property("mode").toInt())); @@ -522,13 +527,13 @@ void RenderProcessor::ProcessAudioFootage(SampleBuffer &destination, const Foota } } -void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, const ShaderJob &job) +void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, const ShaderJob *job) { if (!render_ctx_) { return; } - QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID()); + QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job->GetShaderID()); QMutexLocker locker(shader_cache_->mutex()); @@ -536,16 +541,20 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, co if (shader.isNull()) { // Since we have shader code, compile it now - shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID())); + shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job->GetShaderID())); if (shader.isNull()) { // Couldn't find or build the shader required return; } + + shader_cache_->insert(full_shader_id, shader); } + locker.unlock(); + // Run shader - render_ctx_->BlitToTexture(shader, job, destination.get()); + render_ctx_->BlitToTexture(shader, *job, destination.get()); } void RenderProcessor::ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job) @@ -579,16 +588,16 @@ void RenderProcessor::ProcessSamples(SampleBuffer &destination, const Node *node } } -void RenderProcessor::ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob &job) +void RenderProcessor::ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob *job) { if (!render_ctx_) { return; } - render_ctx_->BlitColorManaged(job, destination.get()); + render_ctx_->BlitColorManaged(*job, destination.get()); } -void RenderProcessor::ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob &job) +void RenderProcessor::ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob *job) { if (!render_ctx_) { return; @@ -599,14 +608,14 @@ void RenderProcessor::ProcessFrameGeneration(TexturePtr destination, const Node frame->set_video_params(destination->params()); frame->allocate(); - node->GenerateFrame(frame, job); + node->GenerateFrame(frame, *job); destination->Upload(frame->data(), frame->linesize_pixels()); } -TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob &val) +TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob *val) { - FramePtr frame = FrameHashCache::LoadCacheFrame(val.GetFilename()); + FramePtr frame = FrameHashCache::LoadCacheFrame(val->GetFilename()); if (frame) { TexturePtr tex = CreateTexture(frame->video_params()); if (tex) { @@ -615,7 +624,7 @@ TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob &val) } } else { QStringList s = ticket_->property("badcache").toStringList(); - s.append(val.GetFilename()); + s.append(val->GetFilename()); ticket_->setProperty("badcache", s); } diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 8ef6699bb..37924181f 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -44,19 +44,19 @@ public: protected: virtual NodeValueTable GenerateBlockTable(const Track *track, const TimeRange &range) override; - virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time) override; + virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob *stream, const rational &input_time) override; - virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time) override; + virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob *stream, const TimeRange &input_time) override; - virtual void ProcessShader(TexturePtr destination, const Node *node, const ShaderJob& job) override; + virtual void ProcessShader(TexturePtr destination, const Node *node, const ShaderJob *job) override; virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job) override; - virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job) override; + virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob *job) override; - virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job) override; + virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob *job) override; - virtual TexturePtr ProcessVideoCacheJob(const CacheJob &val) override; + virtual TexturePtr ProcessVideoCacheJob(const CacheJob *val) override; virtual TexturePtr CreateTexture(const VideoParams &p) override; diff --git a/app/render/texture.cpp b/app/render/texture.cpp index 2c5c9fdea..7903f486a 100644 --- a/app/render/texture.cpp +++ b/app/render/texture.cpp @@ -31,6 +31,10 @@ Texture::~Texture() if (renderer_) { renderer_->DestroyTexture(this); } + + if (job_) { + delete job_; + } } void Texture::Upload(void *data, int linesize) diff --git a/app/render/texture.h b/app/render/texture.h index 6179878a8..942c0c4f6 100644 --- a/app/render/texture.h +++ b/app/render/texture.h @@ -27,8 +27,12 @@ namespace olive { +class AcceleratedJob; class Renderer; +class Texture; +using TexturePtr = std::shared_ptr; + class Texture { public: @@ -45,17 +49,26 @@ public: */ Texture(const VideoParams& param) : renderer_(nullptr), - params_(param) + params_(param), + job_(nullptr) { } + template + Texture(const VideoParams &p, const T &j) : + Texture(p) + { + job_ = new T(j); + } + /** * @brief Construct a real texture linked to a renderer backend */ Texture(Renderer* renderer, const QVariant& native, const VideoParams& param) : renderer_(renderer), params_(param), - id_(native) + id_(native), + job_(nullptr) { } @@ -71,6 +84,18 @@ public: return params_; } + template + static TexturePtr Job(const VideoParams &p, const T &j) + { + return std::make_shared(p, j); + } + + template + TexturePtr toJob(const T &job) + { + return Texture::Job(params_, job); + } + void Upload(void* data, int linesize); void Download(void* data, int linesize); @@ -90,6 +115,11 @@ public: return params_.effective_height(); } + QVector2D virtual_resolution() const + { + return QVector2D(params_.square_pixel_width(), params_.height()); + } + VideoParams::Format format() const { return params_.format(); @@ -115,6 +145,9 @@ public: return renderer_; } + bool IsJob() const { return job_; } + AcceleratedJob *job() const { return job_; } + private: Renderer* renderer_; @@ -122,9 +155,9 @@ private: QVariant id_; -}; + AcceleratedJob *job_; -using TexturePtr = std::shared_ptr; +}; }