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:
Diffstat (limited to 'source/blender/compositor/operations')
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.cc45
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc40
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.cc73
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cc555
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.h89
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cc32
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.h12
11 files changed, 871 insertions, 13 deletions
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cc b/source/blender/compositor/operations/COM_BrightnessOperation.cc
index 92cab47318a..7878eca2bbd 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.cc
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc
@@ -28,6 +28,7 @@ BrightnessOperation::BrightnessOperation()
this->addOutputSocket(DataType::Color);
this->m_inputProgram = nullptr;
this->m_use_premultiply = false;
+ flags.can_be_constant = true;
}
void BrightnessOperation::setUsePremultiply(bool use_premultiply)
@@ -85,6 +86,50 @@ void BrightnessOperation::executePixelSampled(float output[4],
}
}
+void BrightnessOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ float tmp_color[4];
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float *in_color = it.in(0);
+ const float brightness = *it.in(1) / 100.0f;
+ const float contrast = *it.in(2);
+ float delta = contrast / 200.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ float a, b;
+ if (contrast > 0) {
+ a = 1.0f - delta * 2.0f;
+ a = 1.0f / max_ff(a, FLT_EPSILON);
+ b = a * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ a = max_ff(1.0f - delta * 2.0f, 0.0f);
+ b = a * brightness + delta;
+ }
+ const float *color;
+ if (this->m_use_premultiply) {
+ premul_to_straight_v4_v4(tmp_color, in_color);
+ color = tmp_color;
+ }
+ else {
+ color = in_color;
+ }
+ it.out[0] = a * color[0] + b;
+ it.out[1] = a * color[1] + b;
+ it.out[2] = a * color[2] + b;
+ it.out[3] = color[3];
+ if (this->m_use_premultiply) {
+ straight_to_premul_v4(it.out);
+ }
+ }
+}
+
void BrightnessOperation::deinitExecution()
{
this->m_inputProgram = nullptr;
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.h b/source/blender/compositor/operations/COM_BrightnessOperation.h
index 7c33e0b35ec..64b4fa0dbe2 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.h
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class BrightnessOperation : public NodeOperation {
+class BrightnessOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
@@ -52,6 +52,10 @@ class BrightnessOperation : public NodeOperation {
void deinitExecution() override;
void setUsePremultiply(bool use_premultiply);
+
+ 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_DoubleEdgeMaskOperation.cc b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
index c4099a6d33d..1a0d7e52b0f 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
@@ -1318,6 +1318,7 @@ DoubleEdgeMaskOperation::DoubleEdgeMaskOperation()
this->m_adjacentOnly = false;
this->m_keepInside = false;
this->flags.complex = true;
+ is_output_rendered_ = false;
}
bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/,
@@ -1382,4 +1383,43 @@ void DoubleEdgeMaskOperation::deinitExecution()
}
}
+void DoubleEdgeMaskOperation::get_area_of_interest(int UNUSED(input_idx),
+ const rcti &UNUSED(output_area),
+ rcti &r_input_area)
+{
+ r_input_area.xmax = this->getWidth();
+ r_input_area.xmin = 0;
+ r_input_area.ymax = this->getHeight();
+ r_input_area.ymin = 0;
+}
+
+void DoubleEdgeMaskOperation::update_memory_buffer(MemoryBuffer *output,
+ const rcti &UNUSED(area),
+ Span<MemoryBuffer *> inputs)
+{
+ if (!is_output_rendered_) {
+ /* Ensure full buffers to work with no strides. */
+ MemoryBuffer *input_inner_mask = inputs[0];
+ MemoryBuffer *inner_mask = input_inner_mask->is_a_single_elem() ? input_inner_mask->inflate() :
+ input_inner_mask;
+ MemoryBuffer *input_outer_mask = inputs[1];
+ MemoryBuffer *outer_mask = input_outer_mask->is_a_single_elem() ? input_outer_mask->inflate() :
+ input_outer_mask;
+
+ BLI_assert(output->getWidth() == this->getWidth());
+ BLI_assert(output->getHeight() == this->getHeight());
+ /* TODO(manzanilla): Once tiled implementation is removed, use execution system to run
+ * multi-threaded where possible. */
+ doDoubleEdgeMask(inner_mask->getBuffer(), outer_mask->getBuffer(), output->getBuffer());
+ is_output_rendered_ = true;
+
+ if (inner_mask != input_inner_mask) {
+ delete inner_mask;
+ }
+ if (outer_mask != input_outer_mask) {
+ delete outer_mask;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
index e956e8edc3e..45a80bbbbf0 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
@@ -31,8 +31,12 @@ class DoubleEdgeMaskOperation : public NodeOperation {
SocketReader *m_inputInnerMask;
bool m_adjacentOnly;
bool m_keepInside;
+
+ /* TODO(manzanilla): To be removed with tiled implementation. */
float *m_cachedInstance;
+ bool is_output_rendered_;
+
public:
DoubleEdgeMaskOperation();
@@ -66,6 +70,12 @@ class DoubleEdgeMaskOperation : public NodeOperation {
{
this->m_keepInside = keepInside;
}
+
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
+
+ void update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
index 5a4503fecec..eb1fd98a590 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
@@ -20,6 +20,8 @@
#include "BLI_math.h"
#include "DNA_node_types.h"
+#include <functional>
+
namespace blender::compositor {
EllipseMaskOperation::EllipseMaskOperation()
@@ -114,6 +116,77 @@ void EllipseMaskOperation::executePixelSampled(float output[4],
}
}
+void EllipseMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ MaskFunc mask_func;
+ switch (m_maskType) {
+ case CMP_NODE_MASKTYPE_ADD:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ return is_inside ? MAX2(mask[0], value[0]) : mask[0];
+ };
+ break;
+ case CMP_NODE_MASKTYPE_SUBTRACT:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ return is_inside ? CLAMPIS(mask[0] - value[0], 0, 1) : mask[0];
+ };
+ break;
+ case CMP_NODE_MASKTYPE_MULTIPLY:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ return is_inside ? mask[0] * value[0] : 0;
+ };
+ break;
+ case CMP_NODE_MASKTYPE_NOT:
+ mask_func = [](const bool is_inside, const float *mask, const float *value) {
+ if (is_inside) {
+ return mask[0] > 0.0f ? 0.0f : value[0];
+ }
+ return mask[0];
+ };
+ break;
+ }
+ apply_mask(output, area, inputs, mask_func);
+}
+
+void EllipseMaskOperation::apply_mask(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
+ MaskFunc mask_func)
+{
+ const MemoryBuffer *input_mask = inputs[0];
+ const MemoryBuffer *input_value = inputs[1];
+ const float op_w = this->getWidth();
+ const float op_h = this->getHeight();
+ const float half_w = this->m_data->width / 2.0f;
+ const float half_h = this->m_data->height / 2.0f;
+ const float tx = half_w * half_w;
+ const float ty = half_h * half_h;
+ for (const int y : YRange(area)) {
+ const float op_ry = y / op_h;
+ const float dy = (op_ry - this->m_data->y) / m_aspectRatio;
+ float *out = output->get_elem(area.xmin, y);
+ const float *mask = input_mask->get_elem(area.xmin, y);
+ const float *value = input_value->get_elem(area.xmin, y);
+ for (const int x : XRange(area)) {
+ const float op_rx = x / op_w;
+ const float dx = op_rx - this->m_data->x;
+ const float rx = this->m_data->x + (m_cosine * dx + m_sine * dy);
+ const float ry = this->m_data->y + (-m_sine * dx + m_cosine * dy);
+ float sx = rx - this->m_data->x;
+ sx *= sx;
+ float sy = ry - this->m_data->y;
+ sy *= sy;
+ const bool inside = ((sx / tx) + (sy / ty)) < 1.0f;
+ out[0] = mask_func(inside, mask, value);
+
+ mask += input_mask->elem_stride;
+ value += input_value->elem_stride;
+ out += output->elem_stride;
+ }
+ }
+}
+
void EllipseMaskOperation::deinitExecution()
{
this->m_inputMask = nullptr;
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.h b/source/blender/compositor/operations/COM_EllipseMaskOperation.h
index 64afe0145cf..fba3f979d26 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.h
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.h
@@ -18,12 +18,14 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class EllipseMaskOperation : public NodeOperation {
+class EllipseMaskOperation : public MultiThreadedOperation {
private:
+ using MaskFunc = std::function<float(bool is_inside, const float *mask, const float *value)>;
+
/**
* Cached reference to the inputProgram
*/
@@ -64,6 +66,16 @@ class EllipseMaskOperation : public NodeOperation {
{
this->m_maskType = maskType;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+
+ private:
+ void apply_mask(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
+ MaskFunc mask_func);
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc
index 58fa09fa2a8..77ecbf60356 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cc
+++ b/source/blender/compositor/operations/COM_MixOperation.cc
@@ -35,6 +35,7 @@ MixBaseOperation::MixBaseOperation()
this->m_inputColor2Operation = nullptr;
this->setUseValueAlphaMultiply(false);
this->setUseClamp(false);
+ flags.can_be_constant = true;
}
void MixBaseOperation::initExecution()
@@ -97,6 +98,45 @@ void MixBaseOperation::deinitExecution()
this->m_inputColor2Operation = nullptr;
}
+void MixBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_value = inputs[0];
+ const MemoryBuffer *input_color1 = inputs[1];
+ const MemoryBuffer *input_color2 = inputs[2];
+ const int width = BLI_rcti_size_x(&area);
+ PixelCursor p;
+ p.out_stride = output->elem_stride;
+ p.value_stride = input_value->elem_stride;
+ p.color1_stride = input_color1->elem_stride;
+ p.color2_stride = input_color2->elem_stride;
+ for (const int y : YRange(area)) {
+ p.out = output->get_elem(area.xmin, y);
+ p.row_end = p.out + width * output->elem_stride;
+ p.value = input_value->get_elem(area.xmin, y);
+ p.color1 = input_color1->get_elem(area.xmin, y);
+ p.color2 = input_color2->get_elem(area.xmin, y);
+ update_memory_buffer_row(p);
+ }
+}
+
+void MixBaseOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ p.out[0] = value_m * p.color1[0] + value * p.color2[0];
+ p.out[1] = value_m * p.color1[1] + value * p.color2[1];
+ p.out[2] = value_m * p.color1[2] + value * p.color2[2];
+ p.out[3] = p.color1[3];
+ p.next();
+ }
+}
+
/* ******** Mix Add Operation ******** */
void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
@@ -121,6 +161,23 @@ void MixAddOperation::executePixelSampled(float output[4], float x, float y, Pix
clampIfNeeded(output);
}
+void MixAddOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ p.out[0] = p.color1[0] + value * p.color2[0];
+ p.out[1] = p.color1[1] + value * p.color2[1];
+ p.out[2] = p.color1[2] + value * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Blend Operation ******** */
void MixBlendOperation::executePixelSampled(float output[4],
@@ -150,6 +207,24 @@ void MixBlendOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixBlendOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ float value_m = 1.0f - value;
+ p.out[0] = value_m * p.color1[0] + value * p.color2[0];
+ p.out[1] = value_m * p.color1[1] + value * p.color2[1];
+ p.out[2] = value_m * p.color1[2] + value * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Burn Operation ******** */
void MixColorBurnOperation::executePixelSampled(float output[4],
@@ -228,6 +303,48 @@ void MixColorBurnOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixColorBurnOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float tmp = value_m + value * p.color2[0];
+ if (tmp <= 0.0f) {
+ p.out[0] = 0.0f;
+ }
+ else {
+ tmp = 1.0f - (1.0f - p.color1[0]) / tmp;
+ p.out[0] = CLAMPIS(tmp, 0.0f, 1.0f);
+ }
+
+ tmp = value_m + value * p.color2[1];
+ if (tmp <= 0.0f) {
+ p.out[1] = 0.0f;
+ }
+ else {
+ tmp = 1.0f - (1.0f - p.color1[1]) / tmp;
+ p.out[1] = CLAMPIS(tmp, 0.0f, 1.0f);
+ }
+
+ tmp = value_m + value * p.color2[2];
+ if (tmp <= 0.0f) {
+ p.out[2] = 0.0f;
+ }
+ else {
+ tmp = 1.0f - (1.0f - p.color1[2]) / tmp;
+ p.out[2] = CLAMPIS(tmp, 0.0f, 1.0f);
+ }
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Color Operation ******** */
void MixColorOperation::executePixelSampled(float output[4],
@@ -268,6 +385,36 @@ void MixColorOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixColorOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float colH, colS, colV;
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ if (colS != 0.0f) {
+ float rH, rS, rV;
+ float tmpr, tmpg, tmpb;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
+ p.out[0] = (value_m * p.color1[0]) + (value * tmpr);
+ p.out[1] = (value_m * p.color1[1]) + (value * tmpg);
+ p.out[2] = (value_m * p.color1[2]) + (value * tmpb);
+ }
+ else {
+ copy_v3_v3(p.out, p.color1);
+ }
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Darken Operation ******** */
void MixDarkenOperation::executePixelSampled(float output[4],
@@ -296,6 +443,24 @@ void MixDarkenOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDarkenOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ float value_m = 1.0f - value;
+ p.out[0] = min_ff(p.color1[0], p.color2[0]) * value + p.color1[0] * value_m;
+ p.out[1] = min_ff(p.color1[1], p.color2[1]) * value + p.color1[1] * value_m;
+ p.out[2] = min_ff(p.color1[2], p.color2[2]) * value + p.color1[2] * value_m;
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Difference Operation ******** */
void MixDifferenceOperation::executePixelSampled(float output[4],
@@ -324,6 +489,24 @@ void MixDifferenceOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDifferenceOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ p.out[0] = value_m * p.color1[0] + value * fabsf(p.color1[0] - p.color2[0]);
+ p.out[1] = value_m * p.color1[1] + value * fabsf(p.color1[1] - p.color2[1]);
+ p.out[2] = value_m * p.color1[2] + value * fabsf(p.color1[2] - p.color2[2]);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Difference Operation ******** */
void MixDivideOperation::executePixelSampled(float output[4],
@@ -369,6 +552,41 @@ void MixDivideOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDivideOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ if (p.color2[0] != 0.0f) {
+ p.out[0] = value_m * (p.color1[0]) + value * (p.color1[0]) / p.color2[0];
+ }
+ else {
+ p.out[0] = 0.0f;
+ }
+ if (p.color2[1] != 0.0f) {
+ p.out[1] = value_m * (p.color1[1]) + value * (p.color1[1]) / p.color2[1];
+ }
+ else {
+ p.out[1] = 0.0f;
+ }
+ if (p.color2[2] != 0.0f) {
+ p.out[2] = value_m * (p.color1[2]) + value * (p.color1[2]) / p.color2[2];
+ }
+ else {
+ p.out[2] = 0.0f;
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Dodge Operation ******** */
void MixDodgeOperation::executePixelSampled(float output[4],
@@ -452,6 +670,64 @@ void MixDodgeOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixDodgeOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+
+ float tmp;
+ if (p.color1[0] != 0.0f) {
+ tmp = 1.0f - value * p.color2[0];
+ if (tmp <= 0.0f) {
+ p.out[0] = 1.0f;
+ }
+ else {
+ p.out[0] = p.color1[0] / tmp;
+ CLAMP_MAX(p.out[0], 1.0f);
+ }
+ }
+ else {
+ p.out[0] = 0.0f;
+ }
+
+ if (p.color1[1] != 0.0f) {
+ tmp = 1.0f - value * p.color2[1];
+ if (tmp <= 0.0f) {
+ p.out[1] = 1.0f;
+ }
+ else {
+ p.out[1] = p.color1[1] / tmp;
+ CLAMP_MAX(p.out[1], 1.0f);
+ }
+ }
+ else {
+ p.out[1] = 0.0f;
+ }
+
+ if (p.color1[2] != 0.0f) {
+ tmp = 1.0f - value * p.color2[2];
+ if (tmp <= 0.0f) {
+ p.out[2] = 1.0f;
+ }
+ else {
+ p.out[2] = p.color1[2] / tmp;
+ CLAMP_MAX(p.out[2], 1.0f);
+ }
+ }
+ else {
+ p.out[2] = 0.0f;
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Glare Operation ******** */
void MixGlareOperation::executePixelSampled(float output[4],
@@ -487,6 +763,33 @@ void MixGlareOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixGlareOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ const float value = p.value[0];
+ /* Linear interpolation between 3 cases:
+ * value=-1:output=input value=0:output=input+glare value=1:output=glare
+ */
+ float input_weight;
+ float glare_weight;
+ if (value < 0.0f) {
+ input_weight = 1.0f;
+ glare_weight = 1.0f + value;
+ }
+ else {
+ input_weight = 1.0f - value;
+ glare_weight = 1.0f;
+ }
+ p.out[0] = input_weight * MAX2(p.color1[0], 0.0f) + glare_weight * p.color2[0];
+ p.out[1] = input_weight * MAX2(p.color1[1], 0.0f) + glare_weight * p.color2[1];
+ p.out[2] = input_weight * MAX2(p.color1[2], 0.0f) + glare_weight * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Hue Operation ******** */
void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
@@ -524,6 +827,36 @@ void MixHueOperation::executePixelSampled(float output[4], float x, float y, Pix
clampIfNeeded(output);
}
+void MixHueOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float colH, colS, colV;
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ if (colS != 0.0f) {
+ float rH, rS, rV;
+ float tmpr, tmpg, tmpb;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
+ p.out[0] = value_m * p.color1[0] + value * tmpr;
+ p.out[1] = value_m * p.color1[1] + value * tmpg;
+ p.out[2] = value_m * p.color1[2] + value * tmpb;
+ }
+ else {
+ copy_v3_v3(p.out, p.color1);
+ }
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Lighten Operation ******** */
void MixLightenOperation::executePixelSampled(float output[4],
@@ -570,6 +903,30 @@ void MixLightenOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixLightenOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+
+ float tmp = value * p.color2[0];
+ p.out[0] = MAX2(tmp, p.color1[0]);
+
+ tmp = value * p.color2[1];
+ p.out[1] = MAX2(tmp, p.color1[1]);
+
+ tmp = value * p.color2[2];
+ p.out[2] = MAX2(tmp, p.color1[2]);
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Linear Light Operation ******** */
void MixLinearLightOperation::executePixelSampled(float output[4],
@@ -613,6 +970,39 @@ void MixLinearLightOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixLinearLightOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ if (p.color2[0] > 0.5f) {
+ p.out[0] = p.color1[0] + value * (2.0f * (p.color2[0] - 0.5f));
+ }
+ else {
+ p.out[0] = p.color1[0] + value * (2.0f * (p.color2[0]) - 1.0f);
+ }
+ if (p.color2[1] > 0.5f) {
+ p.out[1] = p.color1[1] + value * (2.0f * (p.color2[1] - 0.5f));
+ }
+ else {
+ p.out[1] = p.color1[1] + value * (2.0f * (p.color2[1]) - 1.0f);
+ }
+ if (p.color2[2] > 0.5f) {
+ p.out[2] = p.color1[2] + value * (2.0f * (p.color2[2] - 0.5f));
+ }
+ else {
+ p.out[2] = p.color1[2] + value * (2.0f * (p.color2[2]) - 1.0f);
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Multiply Operation ******** */
void MixMultiplyOperation::executePixelSampled(float output[4],
@@ -641,6 +1031,25 @@ void MixMultiplyOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixMultiplyOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ p.out[0] = p.color1[0] * (value_m + value * p.color2[0]);
+ p.out[1] = p.color1[1] * (value_m + value * p.color2[1]);
+ p.out[2] = p.color1[2] * (value_m + value * p.color2[2]);
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Overlay Operation ******** */
void MixOverlayOperation::executePixelSampled(float output[4],
@@ -686,6 +1095,40 @@ void MixOverlayOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixOverlayOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ if (p.color1[0] < 0.5f) {
+ p.out[0] = p.color1[0] * (value_m + 2.0f * value * p.color2[0]);
+ }
+ else {
+ p.out[0] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[0])) * (1.0f - p.color1[0]);
+ }
+ if (p.color1[1] < 0.5f) {
+ p.out[1] = p.color1[1] * (value_m + 2.0f * value * p.color2[1]);
+ }
+ else {
+ p.out[1] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[1])) * (1.0f - p.color1[1]);
+ }
+ if (p.color1[2] < 0.5f) {
+ p.out[2] = p.color1[2] * (value_m + 2.0f * value * p.color2[2]);
+ }
+ else {
+ p.out[2] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[2])) * (1.0f - p.color1[2]);
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Saturation Operation ******** */
void MixSaturationOperation::executePixelSampled(float output[4],
@@ -723,6 +1166,33 @@ void MixSaturationOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixSaturationOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ float rH, rS, rV;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ if (rS != 0.0f) {
+ float colH, colS, colV;
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ hsv_to_rgb(rH, (value_m * rS + value * colS), rV, &p.out[0], &p.out[1], &p.out[2]);
+ }
+ else {
+ copy_v3_v3(p.out, p.color1);
+ }
+
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Screen Operation ******** */
void MixScreenOperation::executePixelSampled(float output[4],
@@ -752,6 +1222,25 @@ void MixScreenOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixScreenOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+
+ p.out[0] = 1.0f - (value_m + value * (1.0f - p.color2[0])) * (1.0f - p.color1[0]);
+ p.out[1] = 1.0f - (value_m + value * (1.0f - p.color2[1])) * (1.0f - p.color1[1]);
+ p.out[2] = 1.0f - (value_m + value * (1.0f - p.color2[2])) * (1.0f - p.color1[2]);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Soft Light Operation ******** */
void MixSoftLightOperation::executePixelSampled(float output[4],
@@ -793,6 +1282,34 @@ void MixSoftLightOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixSoftLightOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ const float value_m = 1.0f - value;
+ float scr, scg, scb;
+
+ /* First calculate non-fac based Screen mix. */
+ scr = 1.0f - (1.0f - p.color2[0]) * (1.0f - p.color1[0]);
+ scg = 1.0f - (1.0f - p.color2[1]) * (1.0f - p.color1[1]);
+ scb = 1.0f - (1.0f - p.color2[2]) * (1.0f - p.color1[2]);
+
+ p.out[0] = value_m * p.color1[0] +
+ value * ((1.0f - p.color1[0]) * p.color2[0] * p.color1[0] + p.color1[0] * scr);
+ p.out[1] = value_m * p.color1[1] +
+ value * ((1.0f - p.color1[1]) * p.color2[1] * p.color1[1] + p.color1[1] * scg);
+ p.out[2] = value_m * p.color1[2] +
+ value * ((1.0f - p.color1[2]) * p.color2[2] * p.color1[2] + p.color1[2] * scb);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Subtract Operation ******** */
void MixSubtractOperation::executePixelSampled(float output[4],
@@ -820,6 +1337,23 @@ void MixSubtractOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixSubtractOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ p.out[0] = p.color1[0] - value * p.color2[0];
+ p.out[1] = p.color1[1] - value * p.color2[1];
+ p.out[2] = p.color1[2] - value * p.color2[2];
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
/* ******** Mix Value Operation ******** */
void MixValueOperation::executePixelSampled(float output[4],
@@ -851,4 +1385,25 @@ void MixValueOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MixValueOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ while (p.out < p.row_end) {
+ float value = p.value[0];
+ if (this->useValueAlphaMultiply()) {
+ value *= p.color2[3];
+ }
+ float value_m = 1.0f - value;
+
+ float rH, rS, rV;
+ float colH, colS, colV;
+ rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV);
+ rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV);
+ hsv_to_rgb(rH, rS, (value_m * rV + value * colV), &p.out[0], &p.out[1], &p.out[2]);
+ p.out[3] = p.color1[3];
+
+ clampIfNeeded(p.out);
+ p.next();
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h
index 6c241bc5762..7ef9d78d58f 100644
--- a/source/blender/compositor/operations/COM_MixOperation.h
+++ b/source/blender/compositor/operations/COM_MixOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
@@ -27,8 +27,29 @@ namespace blender::compositor {
* it assumes we are in sRGB color space.
*/
-class MixBaseOperation : public NodeOperation {
+class MixBaseOperation : public MultiThreadedOperation {
protected:
+ struct PixelCursor {
+ float *out;
+ const float *row_end;
+ const float *value;
+ const float *color1;
+ const float *color2;
+ int out_stride;
+ int value_stride;
+ int color1_stride;
+ int color2_stride;
+
+ void next()
+ {
+ BLI_assert(out < row_end);
+ out += out_stride;
+ value += value_stride;
+ color1 += color1_stride;
+ color2 += color2_stride;
+ }
+ };
+
/**
* Prefetched reference to the inputProgram
*/
@@ -81,101 +102,165 @@ class MixBaseOperation : public NodeOperation {
{
this->m_useClamp = value;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) final;
+
+ protected:
+ virtual void update_memory_buffer_row(PixelCursor &p);
};
class MixAddOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixBlendOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixColorBurnOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixColorOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDarkenOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDifferenceOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDivideOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixDodgeOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixGlareOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixHueOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixLightenOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixLinearLightOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixMultiplyOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixOverlayOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixSaturationOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixScreenOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixSoftLightOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixSubtractOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
class MixValueOperation : public MixBaseOperation {
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index 3c753591ced..b078d85372d 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -19,9 +19,9 @@
*/
#include "COM_SMAAOperation.h"
+#include "BKE_node.h"
#include "BLI_math.h"
#include "COM_SMAAAreaTexture.h"
-#include "BKE_node.h"
extern "C" {
#include "IMB_colormanagement.h"
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc
index 860f56e23fa..e47396e14a1 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cc
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cc
@@ -191,10 +191,11 @@ void ViewerOperation::initImage()
BLI_thread_unlock(LOCK_DRAW_IMAGE);
}
-void ViewerOperation::updateImage(rcti *rect)
+void ViewerOperation::updateImage(const rcti *rect)
{
+ float *buffer = m_outputBuffer;
IMB_partial_display_buffer_update(this->m_ibuf,
- this->m_outputBuffer,
+ buffer,
nullptr,
getWidth(),
0,
@@ -218,4 +219,31 @@ eCompositorPriority ViewerOperation::getRenderPriority() const
return eCompositorPriority::Low;
}
+void ViewerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ if (!m_outputBuffer) {
+ return;
+ }
+
+ MemoryBuffer output_buffer(
+ m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, getWidth(), getHeight());
+ const MemoryBuffer *input_image = inputs[0];
+ output_buffer.copy_from(input_image, area);
+ if (this->m_useAlphaInput) {
+ const MemoryBuffer *input_alpha = inputs[1];
+ output_buffer.copy_from(input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, 3);
+ }
+
+ if (m_depthBuffer) {
+ MemoryBuffer depth_buffer(
+ m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, getWidth(), getHeight());
+ const MemoryBuffer *input_depth = inputs[2];
+ depth_buffer.copy_from(input_depth, area);
+ }
+
+ updateImage(&area);
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h
index c0f13ff79fc..ed05a7a282d 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.h
+++ b/source/blender/compositor/operations/COM_ViewerOperation.h
@@ -20,15 +20,17 @@
#include "BKE_global.h"
#include "BLI_rect.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_image_types.h"
namespace blender::compositor {
-class ViewerOperation : public NodeOperation {
+class ViewerOperation : public MultiThreadedOperation {
private:
+ /* TODO(manzanilla): To be removed together with tiled implementation. */
float *m_outputBuffer;
float *m_depthBuffer;
+
Image *m_image;
ImageUser *m_imageUser;
bool m_active;
@@ -125,8 +127,12 @@ class ViewerOperation : public NodeOperation {
this->m_displaySettings = displaySettings;
}
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+
private:
- void updateImage(rcti *rect);
+ void updateImage(const rcti *rect);
void initImage();
};