Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cc45
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.h13
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cc95
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc52
-rw-r--r--source/blender/compositor/operations/COM_DisplaceSimpleOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_FlipOperation.cc38
-rw-r--r--source/blender/compositor/operations/COM_FlipOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cc97
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.h21
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cc47
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc99
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.h7
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc115
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cc26
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc54
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc189
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h13
22 files changed, 934 insertions, 57 deletions
diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc
index f12d93bc8d3..12833660fcb 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cc
+++ b/source/blender/compositor/operations/COM_CropOperation.cc
@@ -95,6 +95,22 @@ void CropOperation::executePixelSampled(float output[4], float x, float y, Pixel
}
}
+void CropOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ rcti crop_area;
+ BLI_rcti_init(&crop_area, m_xmin, m_xmax, m_ymin, m_ymax);
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ if (BLI_rcti_isect_pt(&crop_area, it.x, it.y)) {
+ copy_v4_v4(it.out, it.in(0));
+ }
+ else {
+ zero_v4(it.out);
+ }
+ }
+}
+
CropImageOperation::CropImageOperation() : CropBaseOperation()
{
/* pass */
@@ -114,6 +130,18 @@ bool CropImageOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
+void CropImageOperation::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 + this->m_xmin;
+ r_input_area.xmin = output_area.xmin + this->m_xmin;
+ r_input_area.ymax = output_area.ymax + this->m_ymin;
+ r_input_area.ymin = output_area.ymin + this->m_ymin;
+}
+
void CropImageOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
{
@@ -136,4 +164,21 @@ void CropImageOperation::executePixelSampled(float output[4],
}
}
+void CropImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ rcti op_area;
+ BLI_rcti_init(&op_area, 0, getWidth(), 0, getHeight());
+ const MemoryBuffer *input = inputs[0];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ if (BLI_rcti_isect_pt(&op_area, it.x, it.y)) {
+ input->read_elem_checked(it.x + this->m_xmin, it.y + this->m_ymin, it.out);
+ }
+ else {
+ zero_v4(it.out);
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_CropOperation.h b/source/blender/compositor/operations/COM_CropOperation.h
index acdff79a77c..57caa4e5834 100644
--- a/source/blender/compositor/operations/COM_CropOperation.h
+++ b/source/blender/compositor/operations/COM_CropOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class CropBaseOperation : public NodeOperation {
+class CropBaseOperation : public MultiThreadedOperation {
protected:
SocketReader *m_inputOperation;
NodeTwoXYs *m_settings;
@@ -53,6 +53,10 @@ class CropOperation : public CropBaseOperation {
public:
CropOperation();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class CropImageOperation : public CropBaseOperation {
@@ -65,6 +69,11 @@ class CropImageOperation : public CropBaseOperation {
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ 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
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cc b/source/blender/compositor/operations/COM_DisplaceOperation.cc
index 9f3f5cfe489..a4c01fda7ca 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cc
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc
@@ -32,20 +32,30 @@ DisplaceOperation::DisplaceOperation()
this->flags.complex = true;
this->m_inputColorProgram = nullptr;
- this->m_inputVectorProgram = nullptr;
- this->m_inputScaleXProgram = nullptr;
- this->m_inputScaleYProgram = nullptr;
}
void DisplaceOperation::initExecution()
{
this->m_inputColorProgram = this->getInputSocketReader(0);
- this->m_inputVectorProgram = this->getInputSocketReader(1);
- this->m_inputScaleXProgram = this->getInputSocketReader(2);
- this->m_inputScaleYProgram = this->getInputSocketReader(3);
+ NodeOperation *vector = this->getInputSocketReader(1);
+ NodeOperation *scale_x = this->getInputSocketReader(2);
+ NodeOperation *scale_y = this->getInputSocketReader(3);
+ if (execution_model_ == eExecutionModel::Tiled) {
+ vector_read_fn_ = [=](float x, float y, float *out) {
+ vector->readSampled(out, x, y, PixelSampler::Bilinear);
+ };
+ scale_x_read_fn_ = [=](float x, float y, float *out) {
+ scale_x->readSampled(out, x, y, PixelSampler::Nearest);
+ };
+ scale_y_read_fn_ = [=](float x, float y, float *out) {
+ scale_y->readSampled(out, x, y, PixelSampler::Nearest);
+ };
+ }
this->m_width_x4 = this->getWidth() * 4;
this->m_height_x4 = this->getHeight() * 4;
+ input_vector_width_ = vector->getWidth();
+ input_vector_height_ = vector->getHeight();
}
void DisplaceOperation::executePixelSampled(float output[4],
@@ -69,8 +79,8 @@ void DisplaceOperation::executePixelSampled(float output[4],
bool DisplaceOperation::read_displacement(
float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v)
{
- float width = m_inputVectorProgram->getWidth();
- float height = m_inputVectorProgram->getHeight();
+ float width = input_vector_width_;
+ float height = input_vector_height_;
if (x < 0.0f || x >= width || y < 0.0f || y >= height) {
r_u = 0.0f;
r_v = 0.0f;
@@ -78,7 +88,7 @@ bool DisplaceOperation::read_displacement(
}
float col[4];
- m_inputVectorProgram->readSampled(col, x, y, PixelSampler::Bilinear);
+ vector_read_fn_(x, y, col);
r_u = origin[0] - col[0] * xscale;
r_v = origin[1] - col[1] * yscale;
return true;
@@ -90,9 +100,9 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
float uv[2]; /* temporary variables for derivative estimation */
int num;
- m_inputScaleXProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest);
+ scale_x_read_fn_(xy[0], xy[1], col);
float xs = col[0];
- m_inputScaleYProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest);
+ scale_y_read_fn_(xy[0], xy[1], col);
float ys = col[0];
/* clamp x and y displacement to triple image resolution -
* to prevent hangs from huge values mistakenly plugged in eg. z buffers */
@@ -146,9 +156,9 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
void DisplaceOperation::deinitExecution()
{
this->m_inputColorProgram = nullptr;
- this->m_inputVectorProgram = nullptr;
- this->m_inputScaleXProgram = nullptr;
- this->m_inputScaleYProgram = nullptr;
+ vector_read_fn_ = nullptr;
+ scale_x_read_fn_ = nullptr;
+ scale_y_read_fn_ = nullptr;
}
bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input,
@@ -195,4 +205,61 @@ bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input,
return false;
}
+void DisplaceOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ switch (input_idx) {
+ case 0: {
+ r_input_area.xmin = 0;
+ r_input_area.ymin = 0;
+ r_input_area.xmax = getInputOperation(input_idx)->getWidth();
+ r_input_area.ymax = getInputOperation(input_idx)->getHeight();
+ break;
+ }
+ case 1: {
+ r_input_area = output_area;
+ expand_area_for_sampler(r_input_area, PixelSampler::Bilinear);
+ break;
+ }
+ default: {
+ r_input_area = output_area;
+ break;
+ }
+ }
+}
+
+void DisplaceOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),
+ const rcti &UNUSED(area),
+ Span<MemoryBuffer *> inputs)
+{
+ MemoryBuffer *vector = inputs[1];
+ MemoryBuffer *scale_x = inputs[2];
+ MemoryBuffer *scale_y = inputs[3];
+ vector_read_fn_ = [=](float x, float y, float *out) { vector->read_elem_bilinear(x, y, out); };
+ scale_x_read_fn_ = [=](float x, float y, float *out) { scale_x->read_elem_checked(x, y, out); };
+ scale_y_read_fn_ = [=](float x, float y, float *out) { scale_y->read_elem_checked(x, y, out); };
+}
+
+void DisplaceOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_color = inputs[0];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ const float xy[2] = {(float)it.x, (float)it.y};
+ float uv[2];
+ float deriv[2][2];
+
+ pixelTransform(xy, uv, deriv);
+ if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) {
+ input_color->read_elem_bilinear(uv[0], uv[1], it.out);
+ }
+ else {
+ /* EWA filtering (without nearest it gets blurry with NO distortion). */
+ input_color->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out);
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.h b/source/blender/compositor/operations/COM_DisplaceOperation.h
index fd82692f687..5be914ab672 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.h
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.h
@@ -18,23 +18,27 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class DisplaceOperation : public NodeOperation {
+class DisplaceOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
*/
SocketReader *m_inputColorProgram;
- SocketReader *m_inputVectorProgram;
- SocketReader *m_inputScaleXProgram;
- SocketReader *m_inputScaleYProgram;
float m_width_x4;
float m_height_x4;
+ int input_vector_width_;
+ int input_vector_height_;
+
+ std::function<void(float x, float y, float *out)> vector_read_fn_;
+ std::function<void(float x, float y, float *out)> scale_x_read_fn_;
+ std::function<void(float x, float y, float *out)> scale_y_read_fn_;
+
public:
DisplaceOperation();
@@ -62,6 +66,14 @@ class DisplaceOperation : public NodeOperation {
*/
void deinitExecution() override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
+ void update_memory_buffer_started(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+
private:
bool read_displacement(
float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v);
diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
index f4b77f5d32c..e1c531bd49e 100644
--- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
+++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
@@ -132,4 +132,56 @@ bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input,
return false;
}
+void DisplaceSimpleOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ switch (input_idx) {
+ case 0: {
+ r_input_area.xmin = 0;
+ r_input_area.ymin = 0;
+ r_input_area.xmax = getInputOperation(input_idx)->getWidth();
+ r_input_area.ymax = getInputOperation(input_idx)->getHeight();
+ break;
+ }
+ default: {
+ r_input_area = output_area;
+ break;
+ }
+ }
+}
+
+void DisplaceSimpleOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const float width = this->getWidth();
+ const float height = this->getHeight();
+ const MemoryBuffer *input_color = inputs[0];
+ for (BuffersIterator<float> it = output->iterate_with(inputs.drop_front(1), area); !it.is_end();
+ ++it) {
+ float scale_x = *it.in(1);
+ float scale_y = *it.in(2);
+
+ /* Clamp x and y displacement to triple image resolution -
+ * to prevent hangs from huge values mistakenly plugged in eg. z buffers. */
+ CLAMP(scale_x, -m_width_x4, m_width_x4);
+ CLAMP(scale_y, -m_height_x4, m_height_x4);
+
+ /* Main displacement in pixel space. */
+ const float *vector = it.in(0);
+ const float p_dx = vector[0] * scale_x;
+ const float p_dy = vector[1] * scale_y;
+
+ /* Displaced pixel in uv coords, for image sampling. */
+ /* Clamp nodes to avoid glitches. */
+ float u = it.x - p_dx + 0.5f;
+ float v = it.y - p_dy + 0.5f;
+ CLAMP(u, 0.0f, width - 1.0f);
+ CLAMP(v, 0.0f, height - 1.0f);
+
+ input_color->read_elem_checked(u, v, it.out);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h
index 15e6fcd0523..99f52155466 100644
--- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h
+++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class DisplaceSimpleOperation : public NodeOperation {
+class DisplaceSimpleOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
@@ -59,6 +59,11 @@ class DisplaceSimpleOperation : public NodeOperation {
* Deinitialize the execution
*/
void deinitExecution() override;
+
+ 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
diff --git a/source/blender/compositor/operations/COM_FlipOperation.cc b/source/blender/compositor/operations/COM_FlipOperation.cc
index 8afbec4ddbe..d0dc6c0b570 100644
--- a/source/blender/compositor/operations/COM_FlipOperation.cc
+++ b/source/blender/compositor/operations/COM_FlipOperation.cc
@@ -75,4 +75,42 @@ bool FlipOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
+void FlipOperation::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);
+ if (this->m_flipX) {
+ const int w = (int)this->getWidth() - 1;
+ r_input_area.xmax = (w - output_area.xmin) + 1;
+ r_input_area.xmin = (w - output_area.xmax) - 1;
+ }
+ else {
+ r_input_area.xmin = output_area.xmin;
+ r_input_area.xmax = output_area.xmax;
+ }
+ if (this->m_flipY) {
+ const int h = (int)this->getHeight() - 1;
+ r_input_area.ymax = (h - output_area.ymin) + 1;
+ r_input_area.ymin = (h - output_area.ymax) - 1;
+ }
+ else {
+ r_input_area.ymin = output_area.ymin;
+ r_input_area.ymax = output_area.ymax;
+ }
+}
+
+void FlipOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_img = inputs[0];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ const int nx = this->m_flipX ? ((int)this->getWidth() - 1) - it.x : it.x;
+ const int ny = this->m_flipY ? ((int)this->getHeight() - 1) - it.y : it.y;
+ input_img->read_elem(nx, ny, it.out);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_FlipOperation.h b/source/blender/compositor/operations/COM_FlipOperation.h
index f26d587fde6..dba7f82c341 100644
--- a/source/blender/compositor/operations/COM_FlipOperation.h
+++ b/source/blender/compositor/operations/COM_FlipOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class FlipOperation : public NodeOperation {
+class FlipOperation : public MultiThreadedOperation {
private:
SocketReader *m_inputOperation;
bool m_flipX;
@@ -45,6 +45,11 @@ class FlipOperation : public NodeOperation {
{
this->m_flipY = flipY;
}
+
+ 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
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cc b/source/blender/compositor/operations/COM_MapUVOperation.cc
index 74e3d965d41..ad047c619f8 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cc
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cc
@@ -34,10 +34,26 @@ MapUVOperation::MapUVOperation()
this->m_inputColorProgram = nullptr;
}
+void MapUVOperation::init_data()
+{
+ NodeOperation *image_input = get_input_operation(0);
+ image_width_ = image_input->getWidth();
+ image_height_ = image_input->getHeight();
+
+ NodeOperation *uv_input = get_input_operation(1);
+ uv_width_ = uv_input->getWidth();
+ uv_height_ = uv_input->getHeight();
+}
+
void MapUVOperation::initExecution()
{
this->m_inputColorProgram = this->getInputSocketReader(0);
this->m_inputUVProgram = this->getInputSocketReader(1);
+ if (execution_model_ == eExecutionModel::Tiled) {
+ uv_input_read_fn_ = [=](float x, float y, float *out) {
+ this->m_inputUVProgram->readSampled(out, x, y, PixelSampler::Bilinear);
+ };
+ }
}
void MapUVOperation::executePixelSampled(float output[4],
@@ -81,9 +97,7 @@ void MapUVOperation::executePixelSampled(float output[4],
bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha)
{
- float width = m_inputUVProgram->getWidth();
- float height = m_inputUVProgram->getHeight();
- if (x < 0.0f || x >= width || y < 0.0f || y >= height) {
+ if (x < 0.0f || x >= uv_width_ || y < 0.0f || y >= uv_height_) {
r_u = 0.0f;
r_v = 0.0f;
r_alpha = 0.0f;
@@ -91,9 +105,9 @@ bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_
}
float vector[3];
- m_inputUVProgram->readSampled(vector, x, y, PixelSampler::Bilinear);
- r_u = vector[0] * m_inputColorProgram->getWidth();
- r_v = vector[1] * m_inputColorProgram->getHeight();
+ uv_input_read_fn_(x, y, vector);
+ r_u = vector[0] * image_width_;
+ r_v = vector[1] * image_height_;
r_alpha = vector[2];
return true;
}
@@ -186,4 +200,75 @@ bool MapUVOperation::determineDependingAreaOfInterest(rcti *input,
return false;
}
+void MapUVOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ switch (input_idx) {
+ case 0: {
+ r_input_area.xmin = 0;
+ r_input_area.xmax = image_width_;
+ r_input_area.ymin = 0;
+ r_input_area.ymax = image_height_;
+ break;
+ }
+ case 1: {
+ r_input_area = output_area;
+ expand_area_for_sampler(r_input_area, PixelSampler::Bilinear);
+ break;
+ }
+ }
+}
+
+void MapUVOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),
+ const rcti &UNUSED(area),
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *uv_input = inputs[1];
+ uv_input_read_fn_ = [=](float x, float y, float *out) {
+ uv_input->read_elem_bilinear(x, y, out);
+ };
+}
+
+void MapUVOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_image = inputs[0];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ float xy[2] = {(float)it.x, (float)it.y};
+ float uv[2];
+ float deriv[2][2];
+ float alpha;
+ pixelTransform(xy, uv, deriv, alpha);
+ if (alpha == 0.0f) {
+ zero_v4(it.out);
+ continue;
+ }
+
+ /* EWA filtering. */
+ input_image->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out);
+
+ /* UV to alpha threshold. */
+ const float threshold = this->m_alpha * 0.05f;
+ /* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives.
+ * this calculation is not very well defined, should be looked into if it becomes a problem ...
+ */
+ const float du = len_v2(deriv[0]);
+ const float dv = len_v2(deriv[1]);
+ const float factor = 1.0f - threshold * (du / image_width_ + dv / image_height_);
+ if (factor < 0.0f) {
+ alpha = 0.0f;
+ }
+ else {
+ alpha *= factor;
+ }
+
+ /* "premul" */
+ if (alpha < 1.0f) {
+ mul_v4_fl(it.out, alpha);
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.h b/source/blender/compositor/operations/COM_MapUVOperation.h
index eb5f7d49122..65fbcb461c9 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.h
+++ b/source/blender/compositor/operations/COM_MapUVOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class MapUVOperation : public NodeOperation {
+class MapUVOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
@@ -30,8 +30,15 @@ class MapUVOperation : public NodeOperation {
SocketReader *m_inputUVProgram;
SocketReader *m_inputColorProgram;
+ int uv_width_;
+ int uv_height_;
+ int image_width_;
+ int image_height_;
+
float m_alpha;
+ std::function<void(float x, float y, float *out)> uv_input_read_fn_;
+
public:
MapUVOperation();
@@ -49,6 +56,8 @@ class MapUVOperation : public NodeOperation {
void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2], float &r_alpha);
+ void init_data() override;
+
/**
* Initialize the execution
*/
@@ -64,6 +73,14 @@ class MapUVOperation : public NodeOperation {
this->m_alpha = alpha;
}
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
+ void update_memory_buffer_started(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+
private:
bool read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha);
};
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
index c8e045ea117..d3424959061 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
@@ -128,4 +128,51 @@ bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
+void MovieDistortionOperation::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.xmin = output_area.xmin - m_margin[0];
+ r_input_area.ymin = output_area.ymin - m_margin[1];
+ r_input_area.xmax = output_area.xmax + m_margin[0];
+ r_input_area.ymax = output_area.ymax + m_margin[1];
+}
+
+void MovieDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_img = inputs[0];
+ if (this->m_distortion == nullptr) {
+ output->copy_from(input_img, area);
+ return;
+ }
+
+ /* `float overscan = 0.0f;` */
+ const float pixel_aspect = this->m_pixel_aspect;
+ const float w = (float)this->m_width /* `/ (1 + overscan)` */;
+ const float h = (float)this->m_height /* `/ (1 + overscan)` */;
+ const float aspx = w / (float)this->m_calibration_width;
+ const float aspy = h / (float)this->m_calibration_height;
+ float xy[2];
+ float distorted_xy[2];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ xy[0] = (it.x /* `- 0.5 * overscan * w` */) / aspx;
+ xy[1] = (it.y /* `- 0.5 * overscan * h` */) / aspy / pixel_aspect;
+
+ if (this->m_apply) {
+ BKE_tracking_distortion_undistort_v2(this->m_distortion, xy, distorted_xy);
+ }
+ else {
+ BKE_tracking_distortion_distort_v2(this->m_distortion, xy, distorted_xy);
+ }
+
+ const float u = distorted_xy[0] * aspx /* `+ 0.5 * overscan * w` */;
+ const float v = (distorted_xy[1] * aspy /* `+ 0.5 * overscan * h` */) * pixel_aspect;
+ input_img->read_elem_bilinear(u, v, it.out);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
index 631a62f7ebf..69c2f9c269c 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_movieclip_types.h"
#include "MEM_guardedalloc.h"
@@ -26,7 +26,7 @@
namespace blender::compositor {
-class MovieDistortionOperation : public NodeOperation {
+class MovieDistortionOperation : public MultiThreadedOperation {
private:
SocketReader *m_inputOperation;
MovieClip *m_movieClip;
@@ -58,6 +58,11 @@ class MovieDistortionOperation : public NodeOperation {
bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output) override;
+
+ 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
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
index 3577860b93d..d2a06ddd7c4 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
@@ -16,6 +16,7 @@
*/
#include "COM_PlaneCornerPinOperation.h"
+#include "COM_ConstantOperation.h"
#include "COM_ReadBufferOperation.h"
#include "MEM_guardedalloc.h"
@@ -28,6 +29,11 @@
namespace blender::compositor {
+constexpr int LOWER_LEFT_CORNER_INDEX = 0;
+constexpr int LOWER_RIGHT_CORNER_INDEX = 1;
+constexpr int UPPER_RIGHT_CORNER_INDEX = 2;
+constexpr int UPPER_LEFT_CORNER_INDEX = 3;
+
static bool check_corners(float corners[4][2])
{
int i, next, prev;
@@ -58,6 +64,7 @@ static bool check_corners(float corners[4][2])
return true;
}
+/* TODO(manzanilla): to be removed with tiled implementation. */
static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2])
{
for (int i = 0; i < 4; i++) {
@@ -87,6 +94,53 @@ static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float c
}
}
+static void set_default_corner(const int corner_idx, float r_corner[2])
+{
+ BLI_assert(corner_idx >= 0 && corner_idx < 4);
+ switch (corner_idx) {
+ case LOWER_LEFT_CORNER_INDEX:
+ r_corner[0] = 0.0f;
+ r_corner[1] = 0.0f;
+ break;
+ case LOWER_RIGHT_CORNER_INDEX:
+ r_corner[0] = 1.0f;
+ r_corner[1] = 0.0f;
+ break;
+ case UPPER_RIGHT_CORNER_INDEX:
+ r_corner[0] = 1.0f;
+ r_corner[1] = 1.0f;
+ break;
+ case UPPER_LEFT_CORNER_INDEX:
+ r_corner[0] = 0.0f;
+ r_corner[1] = 1.0f;
+ break;
+ }
+}
+
+static void read_input_corners(NodeOperation *op, const int first_input_idx, float r_corners[4][2])
+{
+ for (const int i : IndexRange(4)) {
+ NodeOperation *input = op->get_input_operation(i + first_input_idx);
+ if (input->get_flags().is_constant_operation) {
+ ConstantOperation *corner_input = static_cast<ConstantOperation *>(input);
+ copy_v2_v2(r_corners[i], corner_input->get_constant_elem());
+ }
+ else {
+ set_default_corner(i, r_corners[i]);
+ }
+ }
+
+ /* Convexity check: concave corners need to be prevented, otherwise
+ * #BKE_tracking_homography_between_two_quads will freeze. */
+ if (!check_corners(r_corners)) {
+ /* Revert to default corners. There could be a more elegant solution,
+ * this prevents freezing at least. */
+ for (const int i : IndexRange(4)) {
+ set_default_corner(i, r_corners[i]);
+ }
+ }
+}
+
/* ******** PlaneCornerPinMaskOperation ******** */
PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(false)
@@ -103,6 +157,17 @@ PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(fal
flags.complex = true;
}
+void PlaneCornerPinMaskOperation::init_data()
+{
+ if (execution_model_ == eExecutionModel::FullFrame) {
+ float corners[4][2];
+ read_input_corners(this, 0, corners);
+ calculateCorners(corners, true, 0);
+ }
+}
+
+/* TODO(manzanilla): to be removed with tiled implementation. Same for #deinitExecution and do the
+ * same on #PlaneCornerPinWarpImageOperation. */
void PlaneCornerPinMaskOperation::initExecution()
{
PlaneDistortMaskOperation::initExecution();
@@ -147,10 +212,22 @@ void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect)
void PlaneCornerPinMaskOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
{
+ if (execution_model_ == eExecutionModel::FullFrame) {
+ /* Determine inputs resolution. */
+ PlaneDistortMaskOperation::determineResolution(resolution, preferredResolution);
+ }
resolution[0] = preferredResolution[0];
resolution[1] = preferredResolution[1];
}
+void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_idx),
+ const rcti &UNUSED(output_area),
+ rcti &r_input_area)
+{
+ /* All corner inputs are used as constants. */
+ r_input_area = COM_SINGLE_ELEM_AREA;
+}
+
/* ******** PlaneCornerPinWarpImageOperation ******** */
PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : m_corners_ready(false)
@@ -161,6 +238,15 @@ PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : m_corners
addInputSocket(DataType::Vector);
}
+void PlaneCornerPinWarpImageOperation::init_data()
+{
+ if (execution_model_ == eExecutionModel::FullFrame) {
+ float corners[4][2];
+ read_input_corners(this, 1, corners);
+ calculateCorners(corners, true, 0);
+ }
+}
+
void PlaneCornerPinWarpImageOperation::initExecution()
{
PlaneDistortWarpImageOperation::initExecution();
@@ -227,4 +313,17 @@ bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest(
#endif
}
+void PlaneCornerPinWarpImageOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ if (input_idx == 0) {
+ PlaneDistortWarpImageOperation::get_area_of_interest(input_idx, output_area, r_input_area);
+ }
+ else {
+ /* Corner inputs are used as constants. */
+ r_input_area = COM_SINGLE_ELEM_AREA;
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h
index 91c0cd9e16b..2831e937147 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h
@@ -31,11 +31,13 @@ namespace blender::compositor {
class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation {
private:
+ /* TODO(manzanilla): to be removed with tiled implementation. */
bool m_corners_ready;
public:
PlaneCornerPinMaskOperation();
+ void init_data() override;
void initExecution() override;
void deinitExecution() override;
@@ -43,6 +45,8 @@ class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation {
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) override;
+
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
};
class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation {
@@ -52,6 +56,7 @@ class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation {
public:
PlaneCornerPinWarpImageOperation();
+ void init_data() override;
void initExecution() override;
void deinitExecution() override;
@@ -60,6 +65,8 @@ class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation {
bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output) override;
+
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
index 4edcc206f5b..a80cbbe942a 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
@@ -85,8 +85,9 @@ void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2],
{
PlaneDistortBaseOperation::calculateCorners(corners, normalized, sample);
- const int width = this->m_pixelReader->getWidth();
- const int height = this->m_pixelReader->getHeight();
+ const NodeOperation *image = get_input_operation(0);
+ const int width = image->getWidth();
+ const int height = image->getHeight();
float frame_corners[4][2] = {
{0.0f, 0.0f}, {(float)width, 0.0f}, {(float)width, (float)height}, {0.0f, (float)height}};
MotionSample *sample_data = &this->m_samples[sample];
@@ -127,6 +128,34 @@ void PlaneDistortWarpImageOperation::executePixelSampled(float output[4],
}
}
+void PlaneDistortWarpImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_img = inputs[0];
+ float uv[2];
+ float deriv[2][2];
+ BuffersIterator<float> it = output->iterate_with({}, area);
+ if (this->m_motion_blur_samples == 1) {
+ for (; !it.is_end(); ++it) {
+ warpCoord(it.x, it.y, this->m_samples[0].perspectiveMatrix, uv, deriv);
+ input_img->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out);
+ }
+ }
+ else {
+ for (; !it.is_end(); ++it) {
+ zero_v4(it.out);
+ for (const int sample : IndexRange(this->m_motion_blur_samples)) {
+ float color[4];
+ warpCoord(it.x, it.y, this->m_samples[sample].perspectiveMatrix, uv, deriv);
+ input_img->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], color);
+ add_v4_v4(it.out, color);
+ }
+ mul_v4_fl(it.out, 1.0f / (float)this->m_motion_blur_samples);
+ }
+ }
+}
+
bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(
rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
@@ -157,6 +186,51 @@ bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
+void PlaneDistortWarpImageOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ if (input_idx != 0) {
+ r_input_area = output_area;
+ return;
+ }
+
+ /* TODO: figure out the area needed for warping and EWA filtering. */
+ r_input_area.xmin = 0;
+ r_input_area.ymin = 0;
+ r_input_area.xmax = get_input_operation(0)->getWidth();
+ r_input_area.ymax = get_input_operation(0)->getHeight();
+
+/* Old implemention but resulting coordinates are way out of input operation bounds and in some
+ * cases the area result may incorrectly cause cropping. */
+#if 0
+ float min[2], max[2];
+ INIT_MINMAX2(min, max);
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
+ float UVs[4][2];
+ float deriv[2][2];
+ MotionSample *sample_data = &this->m_samples[sample];
+ /* TODO(sergey): figure out proper way to do this. */
+ warpCoord(
+ output_area.xmin - 2, output_area.ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv);
+ warpCoord(
+ output_area.xmax + 2, output_area.ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv);
+ warpCoord(
+ output_area.xmax + 2, output_area.ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv);
+ warpCoord(
+ output_area.xmin - 2, output_area.ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv);
+ for (int i = 0; i < 4; i++) {
+ minmax_v2v2_v2(min, max, UVs[i]);
+ }
+ }
+
+ r_input_area.xmin = min[0] - 1;
+ r_input_area.ymin = min[1] - 1;
+ r_input_area.xmax = max[0] + 1;
+ r_input_area.ymax = max[1] + 1;
+#endif
+}
+
/* ******** PlaneDistort Mask ******** */
PlaneDistortMaskOperation::PlaneDistortMaskOperation() : PlaneDistortBaseOperation()
@@ -219,4 +293,41 @@ void PlaneDistortMaskOperation::executePixelSampled(float output[4],
}
}
+void PlaneDistortMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ int inside_count = 0;
+ for (const int motion_sample : IndexRange(this->m_motion_blur_samples)) {
+ MotionSample &sample = this->m_samples[motion_sample];
+ inside_count += get_jitter_samples_inside_count(it.x, it.y, sample);
+ }
+ *it.out = (float)inside_count / (this->m_osa * this->m_motion_blur_samples);
+ }
+}
+
+int PlaneDistortMaskOperation::get_jitter_samples_inside_count(int x,
+ int y,
+ MotionSample &sample_data)
+{
+ float point[2];
+ int inside_count = 0;
+ for (int sample = 0; sample < this->m_osa; sample++) {
+ point[0] = x + this->m_jitter[sample][0];
+ point[1] = y + this->m_jitter[sample][1];
+ if (isect_point_tri_v2(point,
+ sample_data.frameSpaceCorners[0],
+ sample_data.frameSpaceCorners[1],
+ sample_data.frameSpaceCorners[2]) ||
+ isect_point_tri_v2(point,
+ sample_data.frameSpaceCorners[0],
+ sample_data.frameSpaceCorners[2],
+ sample_data.frameSpaceCorners[3])) {
+ inside_count++;
+ }
+ }
+ return inside_count;
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
index cc6e4d00d71..3ef9c1dfab8 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
@@ -20,7 +20,7 @@
#include <string.h>
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_movieclip_types.h"
#include "DNA_tracking_types.h"
@@ -32,7 +32,7 @@ namespace blender::compositor {
#define PLANE_DISTORT_MAX_SAMPLES 64
-class PlaneDistortBaseOperation : public NodeOperation {
+class PlaneDistortBaseOperation : public MultiThreadedOperation {
protected:
struct MotionSample {
float frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */
@@ -78,6 +78,11 @@ class PlaneDistortWarpImageOperation : public PlaneDistortBaseOperation {
bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output) override;
+
+ 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;
};
class PlaneDistortMaskOperation : public PlaneDistortBaseOperation {
@@ -91,6 +96,13 @@ class PlaneDistortMaskOperation : public PlaneDistortBaseOperation {
void initExecution() override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+
+ private:
+ int get_jitter_samples_inside_count(int x, int y, MotionSample &sample_data);
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
index 0884f2ad979..bf24f843ca2 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
@@ -101,18 +101,40 @@ void PlaneTrackCommon::determineResolution(unsigned int resolution[2],
/* ******** PlaneTrackMaskOperation ******** */
+void PlaneTrackMaskOperation::init_data()
+{
+ PlaneDistortMaskOperation::init_data();
+ if (execution_model_ == eExecutionModel::FullFrame) {
+ PlaneTrackCommon::read_and_calculate_corners(this);
+ }
+}
+
+/* TODO(manzanilla): to be removed with tiled implementation. */
void PlaneTrackMaskOperation::initExecution()
{
PlaneDistortMaskOperation::initExecution();
- PlaneTrackCommon::read_and_calculate_corners(this);
+ if (execution_model_ == eExecutionModel::Tiled) {
+ PlaneTrackCommon::read_and_calculate_corners(this);
+ }
}
/* ******** PlaneTrackWarpImageOperation ******** */
+void PlaneTrackWarpImageOperation::init_data()
+{
+ PlaneDistortWarpImageOperation::init_data();
+ if (execution_model_ == eExecutionModel::FullFrame) {
+ PlaneTrackCommon::read_and_calculate_corners(this);
+ }
+}
+
+/* TODO(manzanilla): to be removed with tiled implementation. */
void PlaneTrackWarpImageOperation::initExecution()
{
PlaneDistortWarpImageOperation::initExecution();
- PlaneTrackCommon::read_and_calculate_corners(this);
+ if (execution_model_ == eExecutionModel::Tiled) {
+ PlaneTrackCommon::read_and_calculate_corners(this);
+ }
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
index 3bae230aa06..d2027755162 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
@@ -73,6 +73,8 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr
{
}
+ void init_data() override;
+
void initExecution() override;
void determineResolution(unsigned int resolution[2],
@@ -92,6 +94,8 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation,
{
}
+ void init_data() override;
+
void initExecution() override;
void determineResolution(unsigned int resolution[2],
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
index 93702d3f0cf..fcab5dd5751 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
@@ -17,6 +17,8 @@
*/
#include "COM_ProjectorLensDistortionOperation.h"
+#include "COM_ConstantOperation.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -32,6 +34,20 @@ ProjectorLensDistortionOperation::ProjectorLensDistortionOperation()
this->m_dispersionAvailable = false;
this->m_dispersion = 0.0f;
}
+
+void ProjectorLensDistortionOperation::init_data()
+{
+ if (execution_model_ == eExecutionModel::FullFrame) {
+ NodeOperation *dispersion_input = get_input_operation(1);
+ if (dispersion_input->get_flags().is_constant_operation) {
+ this->m_dispersion =
+ static_cast<ConstantOperation *>(dispersion_input)->get_constant_elem()[0];
+ }
+ this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f);
+ this->m_kr2 = this->m_kr * 20;
+ }
+}
+
void ProjectorLensDistortionOperation::initExecution()
{
this->initMutex();
@@ -97,6 +113,7 @@ bool ProjectorLensDistortionOperation::determineDependingAreaOfInterest(
return false;
}
+/* TODO(manzanilla): to be removed with tiled implementation. */
void ProjectorLensDistortionOperation::updateDispersion()
{
if (this->m_dispersionAvailable) {
@@ -114,4 +131,41 @@ void ProjectorLensDistortionOperation::updateDispersion()
this->unlockMutex();
}
+void ProjectorLensDistortionOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ if (input_idx == 1) {
+ /* Dispersion input is used as constant only. */
+ r_input_area = COM_SINGLE_ELEM_AREA;
+ return;
+ }
+
+ r_input_area.ymax = output_area.ymax;
+ r_input_area.ymin = output_area.ymin;
+ r_input_area.xmin = output_area.xmin - this->m_kr2 - 2;
+ r_input_area.xmax = output_area.xmax + this->m_kr2 + 2;
+}
+
+void ProjectorLensDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_image = inputs[0];
+ const float height = this->getHeight();
+ const float width = this->getWidth();
+ float color[4];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ const float v = (it.y + 0.5f) / height;
+ const float u = (it.x + 0.5f) / width;
+ input_image->read_elem_bilinear((u * width + this->m_kr2) - 0.5f, v * height - 0.5f, color);
+ it.out[0] = color[0];
+ input_image->read_elem(it.x, it.y, color);
+ it.out[1] = color[1];
+ input_image->read_elem_bilinear((u * width - this->m_kr2) - 0.5f, v * height - 0.5f, color);
+ it.out[2] = color[2];
+ it.out[3] = 1.0f;
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h
index bce61d3de15..7c7626bf271 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h
@@ -18,12 +18,12 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_node_types.h"
namespace blender::compositor {
-class ProjectorLensDistortionOperation : public NodeOperation {
+class ProjectorLensDistortionOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
@@ -31,6 +31,7 @@ class ProjectorLensDistortionOperation : public NodeOperation {
SocketReader *m_inputProgram;
float m_dispersion;
+ /* TODO(manzanilla): to be removed with tiled implementation. */
bool m_dispersionAvailable;
float m_kr, m_kr2;
@@ -43,6 +44,7 @@ class ProjectorLensDistortionOperation : public NodeOperation {
*/
void executePixel(float output[4], int x, int y, void *data) override;
+ void init_data() override;
/**
* Initialize the execution
*/
@@ -59,6 +61,11 @@ class ProjectorLensDistortionOperation : public NodeOperation {
rcti *output) override;
void updateDispersion();
+
+ 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
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
index 634fe66b0dd..f9ba2ef69ad 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
@@ -17,6 +17,7 @@
*/
#include "COM_ScreenLensDistortionOperation.h"
+#include "COM_ConstantOperation.h"
#include "BLI_math.h"
#include "BLI_rand.h"
@@ -53,6 +54,35 @@ void ScreenLensDistortionOperation::setDispersion(float dispersion)
m_dispersion_const = true;
}
+void ScreenLensDistortionOperation::init_data()
+{
+ this->m_cx = 0.5f * (float)getWidth();
+ this->m_cy = 0.5f * (float)getHeight();
+
+ switch (execution_model_) {
+ case eExecutionModel::FullFrame: {
+ NodeOperation *distortion_op = get_input_operation(1);
+ NodeOperation *dispersion_op = get_input_operation(2);
+ if (!m_distortion_const && distortion_op->get_flags().is_constant_operation) {
+ m_distortion = static_cast<ConstantOperation *>(distortion_op)->get_constant_elem()[0];
+ }
+ if (!m_dispersion_const && distortion_op->get_flags().is_constant_operation) {
+ m_dispersion = static_cast<ConstantOperation *>(dispersion_op)->get_constant_elem()[0];
+ }
+ updateVariables(m_distortion, m_dispersion);
+ break;
+ }
+ case eExecutionModel::Tiled: {
+ /* If both are constant, init variables once. */
+ if (m_distortion_const && m_dispersion_const) {
+ updateVariables(m_distortion, m_dispersion);
+ m_variables_ready = true;
+ }
+ break;
+ }
+ }
+}
+
void ScreenLensDistortionOperation::initExecution()
{
this->m_inputProgram = this->getInputSocketReader(0);
@@ -61,15 +91,6 @@ void ScreenLensDistortionOperation::initExecution()
uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
rng_seed ^= (uint)POINTER_AS_INT(m_inputProgram);
this->m_rng = BLI_rng_new(rng_seed);
-
- this->m_cx = 0.5f * (float)getWidth();
- this->m_cy = 0.5f * (float)getHeight();
-
- /* if both are constant, init variables once */
- if (m_distortion_const && m_dispersion_const) {
- updateVariables(m_distortion, m_dispersion);
- m_variables_ready = true;
- }
}
void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/)
@@ -130,7 +151,7 @@ bool ScreenLensDistortionOperation::get_delta(float r_sq,
return false;
}
-void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer,
+void ScreenLensDistortionOperation::accumulate(const MemoryBuffer *buffer,
int a,
int b,
float r_sq,
@@ -154,7 +175,14 @@ void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer,
float xy[2];
distort_uv(uv, t, xy);
- buffer->readBilinear(color, xy[0], xy[1]);
+ switch (execution_model_) {
+ case eExecutionModel::Tiled:
+ buffer->readBilinear(color, xy[0], xy[1]);
+ break;
+ case eExecutionModel::FullFrame:
+ buffer->read_elem_bilinear(xy[0], xy[1], color);
+ break;
+ }
sum[a] += (1.0f - tz) * color[a];
sum[b] += (tz)*color[b];
@@ -354,4 +382,143 @@ void ScreenLensDistortionOperation::updateVariables(float distortion, float disp
mul_v3_v3fl(m_k4, m_k, 4.0f);
}
+void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx,
+ const rcti &UNUSED(output_area),
+ rcti &r_input_area)
+{
+ if (input_idx != 0) {
+ /* Dispersion and distorsion inputs are used as constants only. */
+ r_input_area = COM_SINGLE_ELEM_AREA;
+ }
+
+ /* XXX the original method of estimating the area-of-interest does not work
+ * it assumes a linear increase/decrease of mapped coordinates, which does not
+ * yield correct results for the area and leaves uninitialized buffer areas.
+ * So now just use the full image area, which may not be as efficient but works at least ...
+ */
+#if 1
+ NodeOperation *image = getInputOperation(0);
+ r_input_area.xmax = image->getWidth();
+ r_input_area.xmin = 0;
+ r_input_area.ymax = image->getHeight();
+ r_input_area.ymin = 0;
+
+#else /* Original method in tiled implementation. */
+ rcti newInput;
+ const float margin = 2;
+
+ BLI_rcti_init_minmax(&newInput);
+
+ if (m_dispersion_const && m_distortion_const) {
+ /* update from fixed distortion/dispersion */
+# define UPDATE_INPUT(x, y) \
+ { \
+ float coords[6]; \
+ determineUV(coords, x, y); \
+ newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
+ newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
+ newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
+ newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
+ } \
+ (void)0
+
+ UPDATE_INPUT(input->xmin, input->xmax);
+ UPDATE_INPUT(input->xmin, input->ymax);
+ UPDATE_INPUT(input->xmax, input->ymax);
+ UPDATE_INPUT(input->xmax, input->ymin);
+
+# undef UPDATE_INPUT
+ }
+ else {
+ /* use maximum dispersion 1.0 if not const */
+ float dispersion = m_dispersion_const ? m_dispersion : 1.0f;
+
+# define UPDATE_INPUT(x, y, distortion) \
+ { \
+ float coords[6]; \
+ updateVariables(distortion, dispersion); \
+ determineUV(coords, x, y); \
+ newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
+ newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
+ newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
+ newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
+ } \
+ (void)0
+
+ if (m_distortion_const) {
+ /* update from fixed distortion */
+ UPDATE_INPUT(input->xmin, input->xmax, m_distortion);
+ UPDATE_INPUT(input->xmin, input->ymax, m_distortion);
+ UPDATE_INPUT(input->xmax, input->ymax, m_distortion);
+ UPDATE_INPUT(input->xmax, input->ymin, m_distortion);
+ }
+ else {
+ /* update from min/max distortion (-1..1) */
+ UPDATE_INPUT(input->xmin, input->xmax, -1.0f);
+ UPDATE_INPUT(input->xmin, input->ymax, -1.0f);
+ UPDATE_INPUT(input->xmax, input->ymax, -1.0f);
+ UPDATE_INPUT(input->xmax, input->ymin, -1.0f);
+
+ UPDATE_INPUT(input->xmin, input->xmax, 1.0f);
+ UPDATE_INPUT(input->xmin, input->ymax, 1.0f);
+ UPDATE_INPUT(input->xmax, input->ymax, 1.0f);
+ UPDATE_INPUT(input->xmax, input->ymin, 1.0f);
+
+# undef UPDATE_INPUT
+ }
+ }
+
+ newInput.xmin -= margin;
+ newInput.ymin -= margin;
+ newInput.xmax += margin;
+ newInput.ymax += margin;
+
+ operation = getInputOperation(0);
+ if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
+ return true;
+ }
+ return false;
+#endif
+}
+
+void ScreenLensDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_image = inputs[0];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ float xy[2] = {(float)it.x, (float)it.y};
+ float uv[2];
+ get_uv(xy, uv);
+ const float uv_dot = len_squared_v2(uv);
+
+ float delta[3][2];
+ const bool valid_r = get_delta(uv_dot, m_k4[0], uv, delta[0]);
+ const bool valid_g = get_delta(uv_dot, m_k4[1], uv, delta[1]);
+ const bool valid_b = get_delta(uv_dot, m_k4[2], uv, delta[2]);
+ if (!(valid_r && valid_g && valid_b)) {
+ zero_v4(it.out);
+ continue;
+ }
+
+ int count[3] = {0, 0, 0};
+ float sum[4] = {0, 0, 0, 0};
+ accumulate(input_image, 0, 1, uv_dot, uv, delta, sum, count);
+ accumulate(input_image, 1, 2, uv_dot, uv, delta, sum, count);
+
+ if (count[0]) {
+ it.out[0] = 2.0f * sum[0] / (float)count[0];
+ }
+ if (count[1]) {
+ it.out[1] = 2.0f * sum[1] / (float)count[1];
+ }
+ if (count[2]) {
+ it.out[2] = 2.0f * sum[2] / (float)count[2];
+ }
+
+ /* Set alpha. */
+ it.out[3] = 1.0f;
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
index 98872bfe142..616fc8883b0 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
@@ -18,14 +18,14 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_node_types.h"
struct RNG;
namespace blender::compositor {
-class ScreenLensDistortionOperation : public NodeOperation {
+class ScreenLensDistortionOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
@@ -50,6 +50,8 @@ class ScreenLensDistortionOperation : public NodeOperation {
public:
ScreenLensDistortionOperation();
+ void init_data() override;
+
/**
* The inner loop of this operation.
*/
@@ -84,6 +86,11 @@ class ScreenLensDistortionOperation : public NodeOperation {
ReadBufferOperation *readOperation,
rcti *output) override;
+ 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;
+
private:
void determineUV(float result[6], float x, float y) const;
void updateVariables(float distortion, float dispersion);
@@ -91,7 +98,7 @@ class ScreenLensDistortionOperation : public NodeOperation {
void get_uv(const float xy[2], float uv[2]) const;
void distort_uv(const float uv[2], float t, float xy[2]) const;
bool get_delta(float r_sq, float k4, const float uv[2], float delta[2]) const;
- void accumulate(MemoryBuffer *buffer,
+ void accumulate(const MemoryBuffer *buffer,
int a,
int b,
float r_sq,