diff options
author | Manuel Castilla <manzanillawork@gmail.com> | 2021-07-26 20:07:08 +0300 |
---|---|---|
committer | Manuel Castilla <manzanillawork@gmail.com> | 2021-07-26 21:13:03 +0300 |
commit | a117794f8c05ad2e2b7db0b0f43c3059f20e62a1 (patch) | |
tree | 8f29140bdbfc0f669f7301f5f3ccc8115bb374f9 /source | |
parent | cf74cd93674c11e8e5ef599100d0c7bf3cc8a79c (diff) |
Compositor: Full frame Scale node
Adds full frame implementation to this node operations.
No functional changes.
Includes a new operation method `init_data` used to initialize any data
needed after operations are linked and resolutions determined.
Once tiled implementation is removed `initExecution` may be renamed
to `init_rendering` and `init_data` to `init_execution`.
Reviewed By: jbakker
Differential Revision: https://developer.blender.org/D11944
Diffstat (limited to 'source')
13 files changed, 265 insertions, 72 deletions
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc index 15450572958..5b48ff8fc08 100644 --- a/source/blender/compositor/intern/COM_ConstantFolder.cc +++ b/source/blender/compositor/intern/COM_ConstantFolder.cc @@ -94,6 +94,7 @@ ConstantOperation *ConstantFolder::fold_operation(NodeOperation *operation) const DataType data_type = operation->getOutputSocket()->getDataType(); MemoryBuffer fold_buf(data_type, first_elem_area_); Vector<MemoryBuffer *> input_bufs = get_constant_input_buffers(operation); + operation->init_data(); operation->render(&fold_buf, {first_elem_area_}, input_bufs); MemoryBuffer *constant_buf = create_constant_buffer(data_type); diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc index 18973bb5a00..1983eb190e2 100644 --- a/source/blender/compositor/intern/COM_Converter.cc +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -518,7 +518,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder, NodeOperation *first = nullptr; ScaleOperation *scaleOperation = nullptr; if (doScale) { - scaleOperation = new ScaleOperation(fromSocket->getDataType()); + scaleOperation = new ScaleRelativeOperation(fromSocket->getDataType()); scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); first = scaleOperation; diff --git a/source/blender/compositor/intern/COM_Enums.cc b/source/blender/compositor/intern/COM_Enums.cc index d218de92544..2f20d2652ba 100644 --- a/source/blender/compositor/intern/COM_Enums.cc +++ b/source/blender/compositor/intern/COM_Enums.cc @@ -17,9 +17,28 @@ */ #include "COM_Enums.h" +#include "BLI_rect.h" namespace blender::compositor { +void expand_area_for_sampler(rcti &area, PixelSampler sampler) +{ + switch (sampler) { + case PixelSampler::Nearest: + break; + case PixelSampler::Bilinear: + area.xmax += 1; + area.ymax += 1; + break; + case PixelSampler::Bicubic: + area.xmin -= 1; + area.xmax += 2; + area.ymin -= 1; + area.ymax += 2; + break; + } +} + std::ostream &operator<<(std::ostream &os, const eCompositorPriority &priority) { switch (priority) { diff --git a/source/blender/compositor/intern/COM_Enums.h b/source/blender/compositor/intern/COM_Enums.h index 519e7df940e..7e5a1b73132 100644 --- a/source/blender/compositor/intern/COM_Enums.h +++ b/source/blender/compositor/intern/COM_Enums.h @@ -22,6 +22,8 @@ #include <ostream> +struct rcti; + namespace blender::compositor { /** @@ -85,6 +87,13 @@ enum class eWorkPackageType { CustomFunction = 1 }; +enum class PixelSampler { + Nearest = 0, + Bilinear = 1, + Bicubic = 2, +}; +void expand_area_for_sampler(rcti &area, PixelSampler sampler); + std::ostream &operator<<(std::ostream &os, const eCompositorPriority &priority); std::ostream &operator<<(std::ostream &os, const eWorkPackageState &execution_state); diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc index 60caf22be1b..cd2738fc2c7 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cc +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc @@ -112,6 +112,9 @@ void ExecutionSystem::set_operations(const Vector<NodeOperation *> &operations, void ExecutionSystem::execute() { DebugInfo::execute_started(this); + for (NodeOperation *op : m_operations) { + op->init_data(); + } execution_model_->execute(*this); } diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index 048ed4c5d6e..ae12c444dc1 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -189,6 +189,25 @@ class MemoryBuffer { return m_buffer + get_coords_offset(x, y); } + void read_elem(int x, int y, float *out) const + { + memcpy(out, get_elem(x, y), m_num_channels * sizeof(float)); + } + + void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const + { + switch (sampler) { + case PixelSampler::Nearest: + this->read_elem(x, y, out); + break; + case PixelSampler::Bilinear: + case PixelSampler::Bicubic: + /* No bicubic. Current implementation produces fuzzy results. */ + this->readBilinear(out, x, y); + break; + } + } + /** * Get channel value at given coordinates. */ @@ -330,7 +349,7 @@ class MemoryBuffer { inline void wrap_pixel(float &x, float &y, MemoryBufferExtend extend_x, - MemoryBufferExtend extend_y) + MemoryBufferExtend extend_y) const { const float w = (float)getWidth(); const float h = (float)getHeight(); @@ -427,7 +446,7 @@ class MemoryBuffer { float x, float y, MemoryBufferExtend extend_x = MemoryBufferExtend::Clip, - MemoryBufferExtend extend_y = MemoryBufferExtend::Clip) + MemoryBufferExtend extend_y = MemoryBufferExtend::Clip) const { float u = x; float v = y; diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc index 4e115cb3f2f..575e8446abe 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cc +++ b/source/blender/compositor/intern/COM_NodeOperation.cc @@ -100,6 +100,11 @@ void NodeOperation::setResolutionInputSocketIndex(unsigned int index) { this->m_resolutionInputSocketIndex = index; } + +void NodeOperation::init_data() +{ + /* Pass. */ +} void NodeOperation::initExecution() { /* pass */ diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index fb9ec1e7a83..934007d25ce 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -75,12 +75,6 @@ enum class ResizeMode { Stretch = NS_CR_STRETCH, }; -enum class PixelSampler { - Nearest = 0, - Bilinear = 1, - Bicubic = 2, -}; - class NodeOperationInput { private: NodeOperation *m_operation; @@ -424,6 +418,12 @@ class NodeOperation { exec_system_ = system; } + /** + * Initializes operation data needed after operations are linked and resolutions determined. For + * rendering heap memory data use initExecution(). + */ + virtual void init_data(); + virtual void initExecution(); /** diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cc b/source/blender/compositor/nodes/COM_ScaleNode.cc index 50d2902f375..819d2e72f30 100644 --- a/source/blender/compositor/nodes/COM_ScaleNode.cc +++ b/source/blender/compositor/nodes/COM_ScaleNode.cc @@ -43,7 +43,7 @@ void ScaleNode::convertToOperations(NodeConverter &converter, switch (bnode->custom1) { case CMP_SCALE_RELATIVE: { - ScaleOperation *operation = new ScaleOperation(); + ScaleRelativeOperation *operation = new ScaleRelativeOperation(); converter.addOperation(operation); converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); @@ -59,7 +59,7 @@ void ScaleNode::convertToOperations(NodeConverter &converter, scaleFactorOperation->setValue(context.getRenderPercentageAsFactor()); converter.addOperation(scaleFactorOperation); - ScaleOperation *operation = new ScaleOperation(); + ScaleRelativeOperation *operation = new ScaleRelativeOperation(); converter.addOperation(operation); converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc index fc72b48eca2..0262f653d1a 100644 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc @@ -43,7 +43,7 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter, MovieClip *clip = (MovieClip *)editorNode->id; bool invert = (editorNode->custom2 & CMP_NODEFLAG_STABILIZE_INVERSE) != 0; - ScaleOperation *scaleOperation = new ScaleOperation(); + ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation(); scaleOperation->setSampler((PixelSampler)editorNode->custom1); RotateOperation *rotateOperation = new RotateOperation(); rotateOperation->setDoDegree2RadConversion(false); diff --git a/source/blender/compositor/nodes/COM_TransformNode.cc b/source/blender/compositor/nodes/COM_TransformNode.cc index cd12939ab43..e1deaf616a4 100644 --- a/source/blender/compositor/nodes/COM_TransformNode.cc +++ b/source/blender/compositor/nodes/COM_TransformNode.cc @@ -40,7 +40,7 @@ void TransformNode::convertToOperations(NodeConverter &converter, NodeInput *angleInput = this->getInputSocket(3); NodeInput *scaleInput = this->getInputSocket(4); - ScaleOperation *scaleOperation = new ScaleOperation(); + ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation(); converter.addOperation(scaleOperation); RotateOperation *rotateOperation = new RotateOperation(); diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc index f03b9fcf34d..2cb61ae746b 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cc +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -17,6 +17,7 @@ */ #include "COM_ScaleOperation.h" +#include "COM_ConstantOperation.h" namespace blender::compositor { @@ -52,13 +53,60 @@ ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation() this->m_inputXOperation = nullptr; this->m_inputYOperation = nullptr; } + +static std::optional<float> get_constant_scale(NodeOperation *op) +{ + if (op->get_flags().is_constant_operation) { + return ((ConstantOperation *)op)->get_constant_elem()[0]; + } + + return std::optional<float>(); +} + +float ScaleOperation::get_constant_scale_x() +{ + std::optional<float> scale_x = get_constant_scale(getInputOperation(1)); + if (scale_x.has_value()) { + return scale_x.value() * get_relative_scale_x_factor(); + } + + return 1.0f; +} + +float ScaleOperation::get_constant_scale_y() +{ + std::optional<float> scale_y = get_constant_scale(getInputOperation(2)); + if (scale_y.has_value()) { + return scale_y.value() * get_relative_scale_y_factor(); + } + + return 1.0f; +} + +BLI_INLINE float scale_coord(const int coord, const float center, const float relative_scale) +{ + return center + (coord - center) / relative_scale; +} + +void ScaleOperation::scale_area(rcti &rect, float scale_x, float scale_y) +{ + rect.xmin = scale_coord(rect.xmin, m_centerX, scale_x); + rect.xmax = scale_coord(rect.xmax, m_centerX, scale_x); + rect.ymin = scale_coord(rect.ymin, m_centerY, scale_y); + rect.ymax = scale_coord(rect.ymax, m_centerY, scale_y); +} + +void ScaleOperation::init_data() +{ + m_centerX = getWidth() / 2.0f; + m_centerY = getHeight() / 2.0f; +} + void ScaleOperation::initExecution() { this->m_inputOperation = this->getInputSocketReader(0); this->m_inputXOperation = this->getInputSocketReader(1); this->m_inputYOperation = this->getInputSocketReader(2); - this->m_centerX = this->getWidth() / 2.0; - this->m_centerY = this->getHeight() / 2.0; } void ScaleOperation::deinitExecution() @@ -68,7 +116,52 @@ void ScaleOperation::deinitExecution() this->m_inputYOperation = nullptr; } -void ScaleOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +void ScaleOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + r_input_area = output_area; + if (input_idx != 0 || m_variable_size) { + return; + } + + float scale_x = get_constant_scale_x(); + float scale_y = get_constant_scale_y(); + scale_area(r_input_area, scale_x, scale_y); + expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler); +} + +void ScaleOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[0]; + MemoryBuffer *input_x = inputs[1]; + MemoryBuffer *input_y = inputs[2]; + const float scale_x_factor = get_relative_scale_x_factor(); + const float scale_y_factor = get_relative_scale_y_factor(); + BuffersIterator<float> it = output->iterate_with({input_x, input_y}, area); + for (; !it.is_end(); ++it) { + const float rel_scale_x = *it.in(0) * scale_x_factor; + const float rel_scale_y = *it.in(1) * scale_y_factor; + const float scaled_x = scale_coord(it.x, m_centerX, rel_scale_x); + const float scaled_y = scale_coord(it.y, m_centerY, rel_scale_y); + input_img->read_elem_sampled(scaled_x, scaled_y, (PixelSampler)m_sampler, it.out); + } +} + +ScaleRelativeOperation::ScaleRelativeOperation() : ScaleOperation() +{ +} + +ScaleRelativeOperation::ScaleRelativeOperation(DataType data_type) : ScaleOperation(data_type) +{ +} + +void ScaleRelativeOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) { PixelSampler effective_sampler = getEffectiveSampler(sampler); @@ -86,9 +179,9 @@ void ScaleOperation::executePixelSampled(float output[4], float x, float y, Pixe this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); } -bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) +bool ScaleRelativeOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) { rcti newInput; if (!m_variable_size) { @@ -115,34 +208,6 @@ bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } -// SCALE ABSOLUTE -ScaleAbsoluteOperation::ScaleAbsoluteOperation() : BaseScaleOperation() -{ - this->addInputSocket(DataType::Color); - this->addInputSocket(DataType::Value); - this->addInputSocket(DataType::Value); - this->addOutputSocket(DataType::Color); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} -void ScaleAbsoluteOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_inputXOperation = this->getInputSocketReader(1); - this->m_inputYOperation = this->getInputSocketReader(2); - this->m_centerX = this->getWidth() / 2.0; - this->m_centerY = this->getHeight() / 2.0; -} - -void ScaleAbsoluteOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} - void ScaleAbsoluteOperation::executePixelSampled(float output[4], float x, float y, @@ -202,8 +267,7 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, newInput.ymax = this->getHeight(); newInput.ymin = 0; } - - return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + return ScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } // Absolute fixed size @@ -215,11 +279,12 @@ ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() this->m_inputOperation = nullptr; this->m_is_offset = false; } -void ScaleFixedSizeOperation::initExecution() + +void ScaleFixedSizeOperation::init_data() { - this->m_inputOperation = this->getInputSocketReader(0); - this->m_relX = this->m_inputOperation->getWidth() / (float)this->m_newWidth; - this->m_relY = this->m_inputOperation->getHeight() / (float)this->m_newHeight; + const NodeOperation *input_op = getInputOperation(0); + this->m_relX = input_op->getWidth() / (float)this->m_newWidth; + this->m_relY = input_op->getHeight() / (float)this->m_newHeight; /* *** all the options below are for a fairly special case - camera framing *** */ if (this->m_offsetX != 0.0f || this->m_offsetY != 0.0f) { @@ -237,8 +302,8 @@ void ScaleFixedSizeOperation::initExecution() if (this->m_is_aspect) { /* apply aspect from clip */ - const float w_src = this->m_inputOperation->getWidth(); - const float h_src = this->m_inputOperation->getHeight(); + const float w_src = input_op->getWidth(); + const float h_src = input_op->getHeight(); /* destination aspect is already applied from the camera frame */ const float w_dst = this->m_newWidth; @@ -267,6 +332,11 @@ void ScaleFixedSizeOperation::initExecution() /* *** end framing options *** */ } +void ScaleFixedSizeOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + void ScaleFixedSizeOperation::deinitExecution() { this->m_inputOperation = nullptr; @@ -315,4 +385,38 @@ void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], resolution[1] = this->m_newHeight; } +void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + BLI_assert(input_idx == 0); + UNUSED_VARS_NDEBUG(input_idx); + r_input_area.xmax = (output_area.xmax - m_offsetX) * this->m_relX; + r_input_area.xmin = (output_area.xmin - m_offsetX) * this->m_relX; + r_input_area.ymax = (output_area.ymax - m_offsetY) * this->m_relY; + r_input_area.ymin = (output_area.ymin - m_offsetY) * this->m_relY; + expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler); +} + +void ScaleFixedSizeOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[0]; + PixelSampler sampler = (PixelSampler)m_sampler; + BuffersIterator<float> it = output->iterate_with({}, area); + if (this->m_is_offset) { + for (; !it.is_end(); ++it) { + const float nx = (it.x - this->m_offsetX) * this->m_relX; + const float ny = (it.y - this->m_offsetY) * this->m_relY; + input_img->read_elem_sampled(nx, ny, sampler, it.out); + } + } + else { + for (; !it.is_end(); ++it) { + input_img->read_elem_sampled(it.x * this->m_relX, it.y * this->m_relY, sampler, it.out); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index 2f9a7be92e6..b2f41a1e98a 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class BaseScaleOperation : public NodeOperation { +class BaseScaleOperation : public MultiThreadedOperation { public: void setSampler(PixelSampler sampler) { @@ -46,7 +46,7 @@ class BaseScaleOperation : public NodeOperation { }; class ScaleOperation : public BaseScaleOperation { - private: + protected: SocketReader *m_inputOperation; SocketReader *m_inputXOperation; SocketReader *m_inputYOperation; @@ -56,31 +56,58 @@ class ScaleOperation : public BaseScaleOperation { public: ScaleOperation(); ScaleOperation(DataType data_type); - bool determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) override; - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void init_data() override; void initExecution() override; void deinitExecution() override; -}; -class ScaleAbsoluteOperation : public BaseScaleOperation { - SocketReader *m_inputOperation; - SocketReader *m_inputXOperation; - SocketReader *m_inputYOperation; - float m_centerX; - float m_centerY; + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + + protected: + virtual float get_relative_scale_x_factor() = 0; + virtual float get_relative_scale_y_factor() = 0; + + private: + float get_constant_scale_x(); + float get_constant_scale_y(); + void scale_area(rcti &rect, float scale_x, float scale_y); +}; +class ScaleRelativeOperation : public ScaleOperation { public: - ScaleAbsoluteOperation(); + ScaleRelativeOperation(); + ScaleRelativeOperation(DataType data_type); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + float get_relative_scale_x_factor() override + { + return 1.0f; + } + float get_relative_scale_y_factor() override + { + return 1.0f; + } +}; - void initExecution() override; - void deinitExecution() override; +class ScaleAbsoluteOperation : public ScaleOperation { + public: + bool determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + float get_relative_scale_x_factor() override + { + return 1.0f / getWidth(); + } + float get_relative_scale_y_factor() override + { + return 1.0f / getHeight(); + } }; class ScaleFixedSizeOperation : public BaseScaleOperation { @@ -108,6 +135,7 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { unsigned int preferredResolution[2]) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void init_data() override; void initExecution() override; void deinitExecution() override; void setNewWidth(int width) @@ -131,6 +159,11 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { this->m_offsetX = x; this->m_offsetY = y; } + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor |