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')
-rw-r--r--source/blender/compositor/CMakeLists.txt13
-rw-r--r--source/blender/compositor/COM_defines.h6
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.cc13
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.h1
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.cc4
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc16
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h5
-rw-r--r--source/blender/compositor/intern/COM_TiledExecutionModel.cc2
-rw-r--r--source/blender/compositor/nodes/COM_MaskNode.cc2
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.cc2
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc30
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverKeyOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc27
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverMixedOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc29
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_BilateralBlurOperation.cc86
-rw-r--r--source/blender/compositor/operations/COM_BilateralBlurOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.cc25
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.cc23
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.cc53
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cc16
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_ConstantOperation.cc17
-rw-r--r--source/blender/compositor/operations/COM_ConstantOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_CryptomatteOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.cc1
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cc46
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc27
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_InvertOperation.cc28
-rw-r--r--source/blender/compositor/operations/COM_InvertOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cc37
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc19
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc35
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cc10
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cc10
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.h3
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cc13
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cc53
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cc124
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cc26
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.cc10
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.cc12
-rw-r--r--source/blender/compositor/operations/COM_ZCombineOperation.cc70
-rw-r--r--source/blender/compositor/operations/COM_ZCombineOperation.h20
60 files changed, 980 insertions, 116 deletions
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 000ba298c2d..ee287c65fe9 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -597,16 +597,16 @@ add_definitions(-DCL_USE_DEPRECATED_OPENCL_1_1_APIS)
set(GENSRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/operations)
set(GENSRC ${GENSRC_DIR}/COM_SMAAAreaTexture.h)
add_custom_command(
- OUTPUT ${GENSRC}
- COMMAND ${CMAKE_COMMAND} -E make_directory ${GENSRC_DIR}
- COMMAND "$<TARGET_FILE:smaa_areatex>" ${GENSRC}
- DEPENDS smaa_areatex
+ OUTPUT ${GENSRC}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${GENSRC_DIR}
+ COMMAND "$<TARGET_FILE:smaa_areatex>" ${GENSRC}
+ DEPENDS smaa_areatex
)
add_custom_target(smaa_areatex_header
- SOURCES ${GENSRC}
+ SOURCES ${GENSRC}
)
list(APPEND SRC
- ${GENSRC}
+ ${GENSRC}
)
unset(GENSRC)
unset(GENSRC_DIR)
@@ -650,4 +650,3 @@ if(WITH_GTESTS)
include(GTestTesting)
blender_add_test_lib(bf_compositor_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
endif()
-
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index 900f29db44c..40a1e0da2a8 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -62,12 +62,18 @@ constexpr int COM_data_type_num_channels(const DataType datatype)
}
}
+constexpr int COM_data_type_bytes_len(DataType data_type)
+{
+ return COM_data_type_num_channels(data_type) * sizeof(float);
+}
+
constexpr int COM_DATA_TYPE_VALUE_CHANNELS = COM_data_type_num_channels(DataType::Value);
constexpr int COM_DATA_TYPE_VECTOR_CHANNELS = COM_data_type_num_channels(DataType::Vector);
constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color);
constexpr float COM_COLOR_TRANSPARENT[4] = {0.0f, 0.0f, 0.0f, 0.0f};
constexpr float COM_VECTOR_ZERO[3] = {0.0f, 0.0f, 0.0f};
+constexpr float COM_COLOR_BLACK[4] = {0.0f, 0.0f, 0.0f, 1.0f};
constexpr float COM_VALUE_ZERO[1] = {0.0f};
constexpr float COM_VALUE_ONE[1] = {1.0f};
diff --git a/source/blender/compositor/intern/COM_BufferOperation.cc b/source/blender/compositor/intern/COM_BufferOperation.cc
index 90c97f2a9c7..cafdff89c8e 100644
--- a/source/blender/compositor/intern/COM_BufferOperation.cc
+++ b/source/blender/compositor/intern/COM_BufferOperation.cc
@@ -32,6 +32,7 @@ BufferOperation::BufferOperation(MemoryBuffer *buffer, DataType data_type)
setResolution(resolution);
addOutputSocket(data_type);
flags.is_constant_operation = buffer_->is_a_single_elem();
+ flags.is_fullframe_operation = false;
}
const float *BufferOperation::get_constant_elem()
@@ -40,20 +41,32 @@ const float *BufferOperation::get_constant_elem()
return buffer_->getBuffer();
}
+void BufferOperation::initExecution()
+{
+ if (buffer_->is_a_single_elem()) {
+ initMutex();
+ }
+}
+
void *BufferOperation::initializeTileData(rcti * /*rect*/)
{
if (buffer_->is_a_single_elem() == false) {
return buffer_;
}
+ lockMutex();
if (!inflated_buffer_) {
inflated_buffer_ = buffer_->inflate();
}
+ unlockMutex();
return inflated_buffer_;
}
void BufferOperation::deinitExecution()
{
+ if (buffer_->is_a_single_elem()) {
+ deinitMutex();
+ }
delete inflated_buffer_;
}
diff --git a/source/blender/compositor/intern/COM_BufferOperation.h b/source/blender/compositor/intern/COM_BufferOperation.h
index 705264c37b7..b4cbc0a56b6 100644
--- a/source/blender/compositor/intern/COM_BufferOperation.h
+++ b/source/blender/compositor/intern/COM_BufferOperation.h
@@ -32,6 +32,7 @@ class BufferOperation : public ConstantOperation {
const float *get_constant_elem() override;
void *initializeTileData(rcti *rect) override;
+ void initExecution() override;
void deinitExecution() override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]) override;
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc
index 5b48ff8fc08..445a9ce7433 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.cc
+++ b/source/blender/compositor/intern/COM_ConstantFolder.cc
@@ -44,7 +44,9 @@ static bool is_constant_foldable(NodeOperation *operation)
{
if (operation->get_flags().can_be_constant && !operation->get_flags().is_constant_operation) {
for (int i = 0; i < operation->getNumberOfInputSockets(); i++) {
- if (!operation->get_input_operation(i)->get_flags().is_constant_operation) {
+ NodeOperation *input = operation->get_input_operation(i);
+ if (!input->get_flags().is_constant_operation ||
+ !static_cast<ConstantOperation *>(input)->can_get_constant_elem()) {
return false;
}
}
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 5443974cbb0..a0333cf96cf 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -178,21 +178,27 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
}
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<OUT_%p>", socket);
switch (socket->getDataType()) {
- case DataType::Value:
- if (typeid(*operation) == typeid(SetValueOperation)) {
- const float value = ((SetValueOperation *)operation)->getValue();
+ case DataType::Value: {
+ ConstantOperation *constant = operation->get_flags().is_constant_operation ?
+ static_cast<ConstantOperation *>(operation) :
+ nullptr;
+ if (constant && constant->can_get_constant_elem()) {
+ const float value = *constant->get_constant_elem();
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value\\n%12.4g", value);
}
else {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value");
}
break;
- case DataType::Vector:
+ }
+ case DataType::Vector: {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector");
break;
- case DataType::Color:
+ }
+ case DataType::Color: {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color");
break;
+ }
}
}
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}");
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index ae12c444dc1..310e87b6a4b 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -260,6 +260,11 @@ class MemoryBuffer {
return this->m_num_channels;
}
+ uint8_t get_elem_bytes_len() const
+ {
+ return this->m_num_channels * sizeof(float);
+ }
+
/**
* Get all buffer elements as a range with no offsets.
*/
diff --git a/source/blender/compositor/intern/COM_TiledExecutionModel.cc b/source/blender/compositor/intern/COM_TiledExecutionModel.cc
index d025ce53330..a081b80349d 100644
--- a/source/blender/compositor/intern/COM_TiledExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_TiledExecutionModel.cc
@@ -45,7 +45,7 @@ TiledExecutionModel::TiledExecutionModel(CompositorContext &context,
group->determineResolution(resolution);
if (border_.use_render_border) {
- const rctf *render_border = border_.viewer_border;
+ const rctf *render_border = border_.render_border;
group->setRenderBorder(
render_border->xmin, render_border->xmax, render_border->ymin, render_border->ymax);
}
diff --git a/source/blender/compositor/nodes/COM_MaskNode.cc b/source/blender/compositor/nodes/COM_MaskNode.cc
index ef171c01653..b5b23798160 100644
--- a/source/blender/compositor/nodes/COM_MaskNode.cc
+++ b/source/blender/compositor/nodes/COM_MaskNode.cc
@@ -41,7 +41,7 @@ void MaskNode::convertToOperations(NodeConverter &converter,
NodeMask *data = (NodeMask *)editorNode->storage;
Mask *mask = (Mask *)editorNode->id;
- // always connect the output image
+ /* Always connect the output image. */
MaskOperation *operation = new MaskOperation();
if (editorNode->custom1 & CMP_NODEFLAG_MASK_FIXED) {
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cc b/source/blender/compositor/nodes/COM_MovieClipNode.cc
index 50bd9b4d71b..b80071d27c7 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.cc
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.cc
@@ -62,7 +62,7 @@ void MovieClipNode::convertToOperations(NodeConverter &converter,
}
}
- // always connect the output image
+ /* Always connect the output image. */
MovieClipOperation *operation = new MovieClipOperation();
operation->setMovieClip(movieClip);
operation->setMovieClipUser(movieClipUser);
diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
index 0c656753a51..30e7fab4027 100644
--- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
+++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
@@ -20,6 +20,11 @@
namespace blender::compositor {
+AlphaOverKeyOperation::AlphaOverKeyOperation()
+{
+ this->flags.can_be_constant = true;
+}
+
void AlphaOverKeyOperation::executePixelSampled(float output[4],
float x,
float y,
@@ -50,4 +55,29 @@ void AlphaOverKeyOperation::executePixelSampled(float output[4],
}
}
+void AlphaOverKeyOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *color1 = p.color1;
+ const float *over_color = p.color2;
+ const float value = *p.value;
+
+ if (over_color[3] <= 0.0f) {
+ copy_v4_v4(p.out, color1);
+ }
+ else if (value == 1.0f && over_color[3] >= 1.0f) {
+ copy_v4_v4(p.out, over_color);
+ }
+ else {
+ const float premul = value * over_color[3];
+ const float mul = 1.0f - premul;
+
+ p.out[0] = (mul * color1[0]) + premul * over_color[0];
+ p.out[1] = (mul * color1[1]) + premul * over_color[1];
+ p.out[2] = (mul * color1[2]) + premul * over_color[2];
+ p.out[3] = (mul * color1[3]) + value * over_color[3];
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h
index 83713d18971..960fbc98fe9 100644
--- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h
+++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h
@@ -28,10 +28,14 @@ namespace blender::compositor {
*/
class AlphaOverKeyOperation : public MixBaseOperation {
public:
+ AlphaOverKeyOperation();
+
/**
* The inner loop of this operation.
*/
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
index c68c79d2263..0cc179ea209 100644
--- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
+++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
@@ -23,6 +23,7 @@ namespace blender::compositor {
AlphaOverMixedOperation::AlphaOverMixedOperation()
{
this->m_x = 0.0f;
+ this->flags.can_be_constant = true;
}
void AlphaOverMixedOperation::executePixelSampled(float output[4],
@@ -56,4 +57,30 @@ void AlphaOverMixedOperation::executePixelSampled(float output[4],
}
}
+void AlphaOverMixedOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *color1 = p.color1;
+ const float *over_color = p.color2;
+ const float value = *p.value;
+
+ if (over_color[3] <= 0.0f) {
+ copy_v4_v4(p.out, color1);
+ }
+ else if (value == 1.0f && over_color[3] >= 1.0f) {
+ copy_v4_v4(p.out, over_color);
+ }
+ else {
+ const float addfac = 1.0f - this->m_x + over_color[3] * this->m_x;
+ const float premul = value * addfac;
+ const float mul = 1.0f - value * over_color[3];
+
+ p.out[0] = (mul * color1[0]) + premul * over_color[0];
+ p.out[1] = (mul * color1[1]) + premul * over_color[1];
+ p.out[2] = (mul * color1[2]) + premul * over_color[2];
+ p.out[3] = (mul * color1[3]) + value * over_color[3];
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h
index e2b3af84162..2b88cd5f421 100644
--- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h
+++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h
@@ -45,6 +45,8 @@ class AlphaOverMixedOperation : public MixBaseOperation {
{
this->m_x = x;
}
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
index 3dd4607e273..a57e8c7f8a3 100644
--- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
+++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
@@ -20,6 +20,11 @@
namespace blender::compositor {
+AlphaOverPremultiplyOperation::AlphaOverPremultiplyOperation()
+{
+ this->flags.can_be_constant = true;
+}
+
void AlphaOverPremultiplyOperation::executePixelSampled(float output[4],
float x,
float y,
@@ -50,4 +55,28 @@ void AlphaOverPremultiplyOperation::executePixelSampled(float output[4],
}
}
+void AlphaOverPremultiplyOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *color1 = p.color1;
+ const float *over_color = p.color2;
+ const float value = *p.value;
+
+ if (over_color[3] <= 0.0f) {
+ copy_v4_v4(p.out, color1);
+ }
+ else if (value == 1.0f && over_color[3] >= 1.0f) {
+ copy_v4_v4(p.out, over_color);
+ }
+ else {
+ const float mul = 1.0f - value * over_color[3];
+
+ p.out[0] = (mul * color1[0]) + value * over_color[0];
+ p.out[1] = (mul * color1[1]) + value * over_color[1];
+ p.out[2] = (mul * color1[2]) + value * over_color[2];
+ p.out[3] = (mul * color1[3]) + value * over_color[3];
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h
index f1d4b668fce..701bc07cc27 100644
--- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h
+++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h
@@ -28,10 +28,14 @@ namespace blender::compositor {
*/
class AlphaOverPremultiplyOperation : public MixBaseOperation {
public:
+ AlphaOverPremultiplyOperation();
+
/**
* The inner loop of this operation.
*/
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
index 64448e2ae95..0c1bb688d4e 100644
--- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
@@ -38,7 +38,6 @@ void BilateralBlurOperation::initExecution()
{
this->m_inputColorProgram = getInputSocketReader(0);
this->m_inputDeterminatorProgram = getInputSocketReader(1);
- this->m_space = this->m_data->sigma_space + this->m_data->iter;
QualityStepHelper::initExecution(COM_QH_INCREASE);
}
@@ -115,4 +114,89 @@ bool BilateralBlurOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
+void BilateralBlurOperation::get_area_of_interest(const int UNUSED(input_idx),
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ const int add = ceil(this->m_space) + 1;
+
+ r_input_area.xmax = output_area.xmax + (add);
+ r_input_area.xmin = output_area.xmin - (add);
+ r_input_area.ymax = output_area.ymax + (add);
+ r_input_area.ymin = output_area.ymin - (add);
+}
+
+struct PixelCursor {
+ MemoryBuffer *input_determinator;
+ MemoryBuffer *input_color;
+ int step;
+ float sigma_color;
+ const float *determ_reference_color;
+ float temp_color[4];
+ float *out;
+ int min_x, max_x;
+ int min_y, max_y;
+};
+
+static void blur_pixel(PixelCursor &p)
+{
+ float blur_divider = 0.0f;
+ zero_v4(p.out);
+
+ /* TODO(sergey): This isn't really good bilateral filter, it should be
+ * using gaussian bell for weights. Also sigma_color doesn't seem to be
+ * used correct at all.
+ */
+ for (int yi = p.min_y; yi < p.max_y; yi += p.step) {
+ for (int xi = p.min_x; xi < p.max_x; xi += p.step) {
+ p.input_determinator->read(p.temp_color, xi, yi);
+ /* Do not take the alpha channel into account. */
+ const float delta_color = (fabsf(p.determ_reference_color[0] - p.temp_color[0]) +
+ fabsf(p.determ_reference_color[1] - p.temp_color[1]) +
+ fabsf(p.determ_reference_color[2] - p.temp_color[2]));
+ if (delta_color < p.sigma_color) {
+ /* Add this to the blur. */
+ p.input_color->read(p.temp_color, xi, yi);
+ add_v4_v4(p.out, p.temp_color);
+ blur_divider += 1.0f;
+ }
+ }
+ }
+
+ if (blur_divider > 0.0f) {
+ mul_v4_fl(p.out, 1.0f / blur_divider);
+ }
+ else {
+ copy_v4_v4(p.out, COM_COLOR_BLACK);
+ }
+}
+
+void BilateralBlurOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ PixelCursor p = {};
+ p.step = QualityStepHelper::getStep();
+ p.sigma_color = this->m_data->sigma_color;
+ p.input_color = inputs[0];
+ p.input_determinator = inputs[1];
+ const float space = this->m_space;
+ for (int y = area.ymin; y < area.ymax; y++) {
+ p.out = output->get_elem(area.xmin, y);
+ /* This will be used as the reference color for the determinator. */
+ p.determ_reference_color = p.input_determinator->get_elem(area.xmin, y);
+ p.min_y = floor(y - space);
+ p.max_y = ceil(y + space);
+ for (int x = area.xmin; x < area.xmax; x++) {
+ p.min_x = floor(x - space);
+ p.max_x = ceil(x + space);
+
+ blur_pixel(p);
+
+ p.determ_reference_color += p.input_determinator->elem_stride;
+ p.out += output->elem_stride;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.h b/source/blender/compositor/operations/COM_BilateralBlurOperation.h
index c56cef35050..517c5292827 100644
--- a/source/blender/compositor/operations/COM_BilateralBlurOperation.h
+++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.h
@@ -18,12 +18,12 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "COM_QualityStepHelper.h"
namespace blender::compositor {
-class BilateralBlurOperation : public NodeOperation, public QualityStepHelper {
+class BilateralBlurOperation : public MultiThreadedOperation, public QualityStepHelper {
private:
SocketReader *m_inputColorProgram;
SocketReader *m_inputDeterminatorProgram;
@@ -55,7 +55,14 @@ class BilateralBlurOperation : public NodeOperation, public QualityStepHelper {
void setData(NodeBilateralBlurData *data)
{
this->m_data = data;
+ this->m_space = data->sigma_space + data->iter;
}
+
+ 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_BokehImageOperation.cc b/source/blender/compositor/operations/COM_BokehImageOperation.cc
index 63f283b6acc..bd5b25b5af8 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.cc
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc
@@ -110,6 +110,31 @@ void BokehImageOperation::executePixelSampled(float output[4],
output[3] = (insideBokehMax + insideBokehMed + insideBokehMin) / 3.0f;
}
+void BokehImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ const float shift = this->m_data->lensshift;
+ const float shift2 = shift / 2.0f;
+ const float distance = this->m_circularDistance;
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ const float insideBokehMax = isInsideBokeh(distance, it.x, it.y);
+ const float insideBokehMed = isInsideBokeh(distance - fabsf(shift2 * distance), it.x, it.y);
+ const float insideBokehMin = isInsideBokeh(distance - fabsf(shift * distance), it.x, it.y);
+ if (shift < 0) {
+ it.out[0] = insideBokehMax;
+ it.out[1] = insideBokehMed;
+ it.out[2] = insideBokehMin;
+ }
+ else {
+ it.out[0] = insideBokehMin;
+ it.out[1] = insideBokehMed;
+ it.out[2] = insideBokehMax;
+ }
+ it.out[3] = (insideBokehMax + insideBokehMed + insideBokehMin) / 3.0f;
+ }
+}
+
void BokehImageOperation::deinitExecution()
{
if (this->m_deleteData) {
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h
index 2e0bc8a34dc..2527233fabd 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.h
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
@@ -49,7 +49,7 @@ namespace blender::compositor {
* With a simple compare it can be detected if the evaluated pixel is between the outer and inner
*edge.
*/
-class BokehImageOperation : public NodeOperation {
+class BokehImageOperation : public MultiThreadedOperation {
private:
/**
* \brief Settings of the bokeh image
@@ -151,6 +151,10 @@ class BokehImageOperation : public NodeOperation {
{
this->m_deleteData = true;
}
+
+ 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_ChangeHSVOperation.cc b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
index eee007ce9e6..1e3e7806968 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
@@ -28,6 +28,7 @@ ChangeHSVOperation::ChangeHSVOperation()
this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Color);
this->m_inputOperation = nullptr;
+ this->flags.can_be_constant = true;
}
void ChangeHSVOperation::initExecution()
@@ -71,4 +72,26 @@ void ChangeHSVOperation::executePixelSampled(float output[4],
output[3] = inputColor1[3];
}
+void ChangeHSVOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float *color = it.in(0);
+ const float hue = *it.in(1);
+ it.out[0] = color[0] + (hue - 0.5f);
+ if (it.out[0] > 1.0f) {
+ it.out[0] -= 1.0f;
+ }
+ else if (it.out[0] < 0.0f) {
+ it.out[0] += 1.0f;
+ }
+ const float saturation = *it.in(2);
+ const float value = *it.in(3);
+ it.out[1] = color[1] * saturation;
+ it.out[2] = color[2] * value;
+ it.out[3] = color[3];
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.h b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
index d38b4be3efe..e7bc3274f25 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.h
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_MixOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
@@ -26,7 +26,7 @@ namespace blender::compositor {
* this program converts an input color to an output value.
* it assumes we are in sRGB color space.
*/
-class ChangeHSVOperation : public NodeOperation {
+class ChangeHSVOperation : public MultiThreadedOperation {
private:
SocketReader *m_inputOperation;
SocketReader *m_hueOperation;
@@ -46,6 +46,10 @@ class ChangeHSVOperation : public NodeOperation {
* The inner loop of this operation.
*/
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;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cc b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
index cb0565a81a2..1b7ad0ea608 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
@@ -98,6 +98,36 @@ void ColorCurveOperation::deinitExecution()
this->m_inputWhiteProgram = nullptr;
}
+void ColorCurveOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ CurveMapping *cumap = this->m_curveMapping;
+ float bwmul[3];
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ /* Local versions of `cumap->black` and `cumap->white`. */
+ const float *black = it.in(2);
+ const float *white = it.in(3);
+ /* Get a local `bwmul` value, it's not threadsafe using `cumap->bwmul` and others. */
+ BKE_curvemapping_set_black_white_ex(black, white, bwmul);
+
+ const float fac = *it.in(0);
+ const float *image = it.in(1);
+ if (fac >= 1.0f) {
+ BKE_curvemapping_evaluate_premulRGBF_ex(cumap, it.out, image, black, bwmul);
+ }
+ else if (fac <= 0.0f) {
+ copy_v3_v3(it.out, image);
+ }
+ else {
+ float col[4];
+ BKE_curvemapping_evaluate_premulRGBF_ex(cumap, col, image, black, bwmul);
+ interp_v3_v3v3(it.out, image, col, fac);
+ }
+ it.out[3] = image[3];
+ }
+}
+
// Constant level curve mapping
ConstantLevelColorCurveOperation::ConstantLevelColorCurveOperation()
@@ -154,4 +184,27 @@ void ConstantLevelColorCurveOperation::deinitExecution()
this->m_inputImageProgram = nullptr;
}
+void ConstantLevelColorCurveOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ CurveMapping *cumap = this->m_curveMapping;
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float fac = *it.in(0);
+ const float *image = it.in(1);
+ if (fac >= 1.0f) {
+ BKE_curvemapping_evaluate_premulRGBF(cumap, it.out, image);
+ }
+ else if (fac <= 0.0f) {
+ copy_v3_v3(it.out, image);
+ }
+ else {
+ float col[4];
+ BKE_curvemapping_evaluate_premulRGBF(cumap, col, image);
+ interp_v3_v3v3(it.out, image, col, fac);
+ }
+ it.out[3] = image[3];
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.h b/source/blender/compositor/operations/COM_ColorCurveOperation.h
index 6fc7759b8d2..d8271e56d1d 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.h
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.h
@@ -51,6 +51,10 @@ class ColorCurveOperation : public CurveBaseOperation {
* Deinitialize the execution
*/
void deinitExecution() override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class ConstantLevelColorCurveOperation : public CurveBaseOperation {
@@ -89,6 +93,10 @@ class ConstantLevelColorCurveOperation : public CurveBaseOperation {
{
copy_v3_v3(this->m_white, white);
}
+
+ 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_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc
index 94d41b28f5d..8752d764107 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cc
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cc
@@ -220,6 +220,22 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
}
}
+void CompositorOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ if (!m_outputBuffer) {
+ return;
+ }
+ MemoryBuffer output_buf(m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, getWidth(), getHeight());
+ output_buf.copy_from(inputs[0], area);
+ if (this->m_useAlphaInput) {
+ output_buf.copy_from(inputs[1], area, 0, COM_DATA_TYPE_VALUE_CHANNELS, 3);
+ }
+ MemoryBuffer depth_buf(m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, getWidth(), getHeight());
+ depth_buf.copy_from(inputs[2], area);
+}
+
void CompositorOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
{
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h
index 65988c86cc5..66367ec8bae 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.h
+++ b/source/blender/compositor/operations/COM_CompositorOperation.h
@@ -20,7 +20,7 @@
#include "BLI_rect.h"
#include "BLI_string.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
struct Scene;
@@ -29,7 +29,7 @@ namespace blender::compositor {
/**
* \brief Compositor output operation
*/
-class CompositorOperation : public NodeOperation {
+class CompositorOperation : public MultiThreadedOperation {
private:
const struct Scene *m_scene;
/**
@@ -125,6 +125,10 @@ class CompositorOperation : public NodeOperation {
{
this->m_active = active;
}
+
+ 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_ConstantOperation.cc b/source/blender/compositor/operations/COM_ConstantOperation.cc
index f905edbde76..33d51cca432 100644
--- a/source/blender/compositor/operations/COM_ConstantOperation.cc
+++ b/source/blender/compositor/operations/COM_ConstantOperation.cc
@@ -22,7 +22,24 @@ namespace blender::compositor {
ConstantOperation::ConstantOperation()
{
+ needs_resolution_to_get_constant_ = false;
flags.is_constant_operation = true;
+ flags.is_fullframe_operation = true;
+}
+
+bool ConstantOperation::can_get_constant_elem() const
+{
+ return !needs_resolution_to_get_constant_ || this->flags.is_resolution_set;
+}
+
+void ConstantOperation::update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ BLI_assert(output->is_a_single_elem());
+ const float *constant = get_constant_elem();
+ float *out = output->get_elem(area.xmin, area.ymin);
+ memcpy(out, constant, output->get_elem_bytes_len());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConstantOperation.h b/source/blender/compositor/operations/COM_ConstantOperation.h
index 2709efeebd8..31b8d30254b 100644
--- a/source/blender/compositor/operations/COM_ConstantOperation.h
+++ b/source/blender/compositor/operations/COM_ConstantOperation.h
@@ -22,15 +22,27 @@
namespace blender::compositor {
+/* TODO(manzanilla): After removing tiled implementation, implement a default #determineResolution
+ * for all constant operations and make all initialization and deinitilization methods final. */
/**
- * Base class for primitive constant operations (Color/Vector/Value). The rest of operations that
- * can be constant are evaluated into primitives during constant folding.
+ * Base class for operations that are always constant. Operations that can be constant only when
+ * all their inputs are so, are evaluated into primitive constants (Color/Vector/Value) during
+ * constant folding.
*/
class ConstantOperation : public NodeOperation {
+ protected:
+ bool needs_resolution_to_get_constant_;
+
public:
ConstantOperation();
+ /** May require resolution to be already determined. */
virtual const float *get_constant_elem() = 0;
+ bool can_get_constant_elem() const;
+
+ void update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) final;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cc b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
index 52ae1d6d5b5..1a86fadad76 100644
--- a/source/blender/compositor/operations/COM_CryptomatteOperation.cc
+++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
@@ -57,8 +57,8 @@ void CryptomatteOperation::executePixel(float output[4], int x, int y, void *dat
::memcpy(&m3hash, &input[0], sizeof(uint32_t));
/* Since the red channel is likely to be out of display range,
* setting green and blue gives more meaningful images. */
- output[1] = ((float)((m3hash << 8)) / (float)UINT32_MAX);
- output[2] = ((float)((m3hash << 16)) / (float)UINT32_MAX);
+ output[1] = ((float)(m3hash << 8) / (float)UINT32_MAX);
+ output[2] = ((float)(m3hash << 16) / (float)UINT32_MAX);
}
for (float hash : m_objectIndex) {
if (input[0] == hash) {
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cc b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
index 8f655964570..3c4b27aa4cf 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
@@ -25,6 +25,7 @@ namespace blender::compositor {
CurveBaseOperation::CurveBaseOperation()
{
this->m_curveMapping = nullptr;
+ this->flags.can_be_constant = true;
}
CurveBaseOperation::~CurveBaseOperation()
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.h b/source/blender/compositor/operations/COM_CurveBaseOperation.h
index fff0f3168ba..da665e7ea60 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.h
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.h
@@ -18,12 +18,12 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_color_types.h"
namespace blender::compositor {
-class CurveBaseOperation : public NodeOperation {
+class CurveBaseOperation : public MultiThreadedOperation {
protected:
/**
* Cached reference to the inputProgram
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
index 2454f507664..a27148f967d 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cc
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
@@ -24,7 +24,7 @@
namespace blender::compositor {
-// DilateErode Distance Threshold
+/* DilateErode Distance Threshold */
DilateErodeThresholdOperation::DilateErodeThresholdOperation()
{
this->addInputSocket(DataType::Value);
@@ -258,7 +258,7 @@ void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device,
device->COM_clEnqueueRange(dilateKernel, outputMemoryBuffer, 7, this);
}
-// Erode Distance
+/* Erode Distance */
ErodeDistanceOperation::ErodeDistanceOperation() : DilateDistanceOperation()
{
/* pass */
@@ -318,7 +318,7 @@ void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device,
device->COM_clEnqueueRange(erodeKernel, outputMemoryBuffer, 7, this);
}
-// Dilate step
+/* Dilate step */
DilateStepOperation::DilateStepOperation()
{
this->addInputSocket(DataType::Value);
@@ -331,7 +331,7 @@ void DilateStepOperation::initExecution()
this->m_inputProgram = this->getInputSocketReader(0);
}
-// small helper to pass data from initializeTileData to executePixel
+/* Small helper to pass data from initializeTileData to executePixel. */
struct tile_info {
rcti rect;
int width;
@@ -370,21 +370,21 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
int bwidth = rect->xmax - rect->xmin;
int bheight = rect->ymax - rect->ymin;
- // NOTE: Cache buffer has original tilesize width, but new height.
- // We have to calculate the additional rows in the first pass,
- // to have valid data available for the second pass.
+ /* NOTE: Cache buffer has original tile-size width, but new height.
+ * We have to calculate the additional rows in the first pass,
+ * to have valid data available for the second pass. */
tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax);
float *rectf = result->buffer;
- // temp holds maxima for every step in the algorithm, buf holds a
- // single row or column of input values, padded with FLT_MAX's to
- // simplify the logic.
+ /* temp holds maxima for every step in the algorithm, buf holds a
+ * single row or column of input values, padded with FLT_MAX's to
+ * simplify the logic. */
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window),
"dilate erode buf");
- // The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
- // first pass, horizontal dilate/erode
+ /* The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
+ * first pass, horizontal dilate/erode. */
for (y = ymin; y < ymax; y++) {
for (x = 0; x < bwidth + 5 * half_window; x++) {
buf[x] = -FLT_MAX;
@@ -409,7 +409,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
}
}
- // second pass, vertical dilate/erode
+ /* Second pass, vertical dilate/erode. */
for (x = 0; x < bwidth; x++) {
for (y = 0; y < bheight + 5 * half_window; y++) {
buf[y] = -FLT_MAX;
@@ -475,7 +475,7 @@ bool DilateStepOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
-// Erode step
+/* Erode step */
ErodeStepOperation::ErodeStepOperation() : DilateStepOperation()
{
/* pass */
@@ -500,21 +500,21 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
int bwidth = rect->xmax - rect->xmin;
int bheight = rect->ymax - rect->ymin;
- // NOTE: Cache buffer has original tilesize width, but new height.
- // We have to calculate the additional rows in the first pass,
- // to have valid data available for the second pass.
+ /* NOTE: Cache buffer has original tile-size width, but new height.
+ * We have to calculate the additional rows in the first pass,
+ * to have valid data available for the second pass. */
tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax);
float *rectf = result->buffer;
- // temp holds maxima for every step in the algorithm, buf holds a
- // single row or column of input values, padded with FLT_MAX's to
- // simplify the logic.
+ /* temp holds maxima for every step in the algorithm, buf holds a
+ * single row or column of input values, padded with FLT_MAX's to
+ * simplify the logic. */
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window),
"dilate erode buf");
- // The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
- // first pass, horizontal dilate/erode
+ /* The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
+ * first pass, horizontal dilate/erode */
for (y = ymin; y < ymax; y++) {
for (x = 0; x < bwidth + 5 * half_window; x++) {
buf[x] = FLT_MAX;
@@ -539,7 +539,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
}
}
- // second pass, vertical dilate/erode
+ /* Second pass, vertical dilate/erode. */
for (x = 0; x < bwidth; x++) {
for (y = 0; y < bheight + 5 * half_window; y++) {
buf[y] = FLT_MAX;
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.h b/source/blender/compositor/operations/COM_GlareBaseOperation.h
index 50db4e02940..6dac6f5ecc7 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.h
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.h
@@ -23,8 +23,8 @@
namespace blender::compositor {
-/* utility functions used by glare, tonemap and lens distortion */
-/* soms macros for color handling */
+/* Utility functions used by glare, tone-map and lens distortion. */
+/* Some macros for color handling. */
typedef float fRGB[4];
/* TODO: replace with BLI_math_vector. */
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
index e341a88ff71..5ae868c5964 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
@@ -73,4 +73,31 @@ void HueSaturationValueCorrectOperation::deinitExecution()
this->m_inputProgram = nullptr;
}
+void HueSaturationValueCorrectOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ float hsv[4];
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ copy_v4_v4(hsv, it.in(0));
+
+ /* Adjust hue, scaling returned default 0.5 up to 1. */
+ float f = BKE_curvemapping_evaluateF(this->m_curveMapping, 0, hsv[0]);
+ hsv[0] += f - 0.5f;
+
+ /* Adjust saturation, scaling returned default 0.5 up to 1. */
+ f = BKE_curvemapping_evaluateF(this->m_curveMapping, 1, hsv[0]);
+ hsv[1] *= (f * 2.0f);
+
+ /* Adjust value, scaling returned default 0.5 up to 1. */
+ f = BKE_curvemapping_evaluateF(this->m_curveMapping, 2, hsv[0]);
+ hsv[2] *= (f * 2.0f);
+
+ hsv[0] = hsv[0] - floorf(hsv[0]); /* Mod 1.0. */
+ CLAMP(hsv[1], 0.0f, 1.0f);
+
+ copy_v4_v4(it.out, hsv);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h
index 703b2894bdb..6c1b66aba1f 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h
@@ -47,6 +47,10 @@ class HueSaturationValueCorrectOperation : public CurveBaseOperation {
* Deinitialize the execution
*/
void deinitExecution() 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_InvertOperation.cc b/source/blender/compositor/operations/COM_InvertOperation.cc
index 339e40a5d1f..4f71a1d0d1d 100644
--- a/source/blender/compositor/operations/COM_InvertOperation.cc
+++ b/source/blender/compositor/operations/COM_InvertOperation.cc
@@ -30,6 +30,7 @@ InvertOperation::InvertOperation()
this->m_color = true;
this->m_alpha = false;
setResolutionInputSocketIndex(1);
+ this->flags.can_be_constant = true;
}
void InvertOperation::initExecution()
{
@@ -70,4 +71,31 @@ void InvertOperation::deinitExecution()
this->m_inputColorProgram = nullptr;
}
+void InvertOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float value = *it.in(0);
+ const float inverted_value = 1.0f - value;
+ const float *color = it.in(1);
+
+ if (this->m_color) {
+ it.out[0] = (1.0f - color[0]) * value + color[0] * inverted_value;
+ it.out[1] = (1.0f - color[1]) * value + color[1] * inverted_value;
+ it.out[2] = (1.0f - color[2]) * value + color[2] * inverted_value;
+ }
+ else {
+ copy_v3_v3(it.out, color);
+ }
+
+ if (this->m_alpha) {
+ it.out[3] = (1.0f - color[3]) * value + color[3] * inverted_value;
+ }
+ else {
+ it.out[3] = color[3];
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_InvertOperation.h b/source/blender/compositor/operations/COM_InvertOperation.h
index 17e5eb95f3e..a084bf5d559 100644
--- a/source/blender/compositor/operations/COM_InvertOperation.h
+++ b/source/blender/compositor/operations/COM_InvertOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class InvertOperation : public NodeOperation {
+class InvertOperation : public MultiThreadedOperation {
private:
/**
* Cached reference to the inputProgram
@@ -59,6 +59,10 @@ class InvertOperation : public NodeOperation {
{
this->m_alpha = alpha;
}
+
+ 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_MaskOperation.cc b/source/blender/compositor/operations/COM_MaskOperation.cc
index c7763f08e71..84992f23924 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cc
+++ b/source/blender/compositor/operations/COM_MaskOperation.cc
@@ -161,4 +161,41 @@ void MaskOperation::executePixelSampled(float output[4],
}
}
+void MaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ Vector<MaskRasterHandle *> handles = get_non_null_handles();
+ if (handles.size() == 0) {
+ output->fill(area, COM_VALUE_ZERO);
+ return;
+ }
+
+ float xy[2];
+ for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+ xy[0] = it.x * m_maskWidthInv + m_mask_px_ofs[0];
+ xy[1] = it.y * m_maskHeightInv + m_mask_px_ofs[1];
+ *it.out = 0.0f;
+ for (MaskRasterHandle *handle : handles) {
+ *it.out += BKE_maskrasterize_handle_sample(handle, xy);
+ }
+
+ /* Until we get better falloff. */
+ *it.out /= m_rasterMaskHandleTot;
+ }
+}
+
+Vector<MaskRasterHandle *> MaskOperation::get_non_null_handles() const
+{
+ Vector<MaskRasterHandle *> handles;
+ for (int i = 0; i < m_rasterMaskHandleTot; i++) {
+ MaskRasterHandle *handle = m_rasterMaskHandles[i];
+ if (handle == nullptr) {
+ continue;
+ }
+ handles.append(handle);
+ }
+ return handles;
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h
index e8cd9c722df..81e344c0451 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.h
+++ b/source/blender/compositor/operations/COM_MaskOperation.h
@@ -19,7 +19,7 @@
#pragma once
#include "BLI_listbase.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_mask_types.h"
#include "IMB_imbuf_types.h"
@@ -31,7 +31,7 @@ namespace blender::compositor {
/**
* Class with implementation of mask rasterization
*/
-class MaskOperation : public NodeOperation {
+class MaskOperation : public MultiThreadedOperation {
protected:
Mask *m_mask;
@@ -98,6 +98,13 @@ class MaskOperation : public NodeOperation {
}
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:
+ Vector<MaskRasterHandle *> get_non_null_handles() const;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
index a9f187258b2..e36e93984fb 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
@@ -29,10 +29,21 @@ MovieClipAttributeOperation::MovieClipAttributeOperation()
this->m_framenumber = 0;
this->m_attribute = MCA_X;
this->m_invert = false;
+ needs_resolution_to_get_constant_ = true;
+ is_value_calculated_ = false;
}
void MovieClipAttributeOperation::initExecution()
{
+ if (!is_value_calculated_) {
+ calc_value();
+ }
+}
+
+void MovieClipAttributeOperation::calc_value()
+{
+ BLI_assert(this->get_flags().is_resolution_set);
+ is_value_calculated_ = true;
if (this->m_clip == nullptr) {
return;
}
@@ -83,4 +94,12 @@ void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2]
resolution[1] = preferredResolution[1];
}
+const float *MovieClipAttributeOperation::get_constant_elem()
+{
+ if (!is_value_calculated_) {
+ calc_value();
+ }
+ return &m_value;
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
index 8507e98d08f..28c39d4dad3 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
@@ -18,6 +18,7 @@
#pragma once
+#include "COM_ConstantOperation.h"
#include "COM_NodeOperation.h"
#include "DNA_movieclip_types.h"
@@ -33,13 +34,14 @@ typedef enum MovieClipAttribute {
* this program converts an input color to an output value.
* it assumes we are in sRGB color space.
*/
-class MovieClipAttributeOperation : public NodeOperation {
+class MovieClipAttributeOperation : public ConstantOperation {
private:
MovieClip *m_clip;
float m_value;
int m_framenumber;
bool m_invert;
MovieClipAttribute m_attribute;
+ bool is_value_calculated_;
public:
/**
@@ -56,6 +58,8 @@ class MovieClipAttributeOperation : public NodeOperation {
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) override;
+ const float *get_constant_elem() override;
+
void setMovieClip(MovieClip *clip)
{
this->m_clip = clip;
@@ -72,6 +76,9 @@ class MovieClipAttributeOperation : public NodeOperation {
{
this->m_invert = invert;
}
+
+ private:
+ void calc_value();
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index 7e896046f01..402d29893a4 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
@@ -160,7 +160,7 @@ int get_datatype_size(DataType datatype)
static float *init_buffer(unsigned int width, unsigned int height, DataType datatype)
{
- // When initializing the tree during initial load the width and height can be zero.
+ /* When initializing the tree during initial load the width and height can be zero. */
if (width != 0 && height != 0) {
int size = get_datatype_size(datatype);
return (float *)MEM_callocN(width * height * size * sizeof(float), "OutputFile buffer");
@@ -294,6 +294,22 @@ void OutputSingleLayerOperation::deinitExecution()
this->m_imageInput = nullptr;
}
+void OutputSingleLayerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ if (!m_outputBuffer) {
+ return;
+ }
+
+ MemoryBuffer output_buf(m_outputBuffer,
+ COM_data_type_num_channels(this->m_datatype),
+ this->getWidth(),
+ this->getHeight());
+ const MemoryBuffer *input_image = inputs[0];
+ output_buf.copy_from(input_image, area);
+}
+
/******************************* MultiLayer *******************************/
OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bool use_layer_)
@@ -444,4 +460,21 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
}
}
+void OutputOpenExrMultiLayerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input_image = inputs[0];
+ for (int i = 0; i < this->m_layers.size(); i++) {
+ OutputOpenExrLayer &layer = this->m_layers[i];
+ if (layer.outputBuffer) {
+ MemoryBuffer output_buf(layer.outputBuffer,
+ COM_data_type_num_channels(layer.datatype),
+ this->getWidth(),
+ this->getHeight());
+ output_buf.copy_from(input_image, area);
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 64ab4c06e7c..057cee0c43e 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "BLI_path_util.h"
#include "BLI_rect.h"
@@ -30,7 +30,7 @@
namespace blender::compositor {
/* Writes the image to a single-layer file. */
-class OutputSingleLayerOperation : public NodeOperation {
+class OutputSingleLayerOperation : public MultiThreadedOperation {
protected:
const RenderData *m_rd;
const bNodeTree *m_tree;
@@ -70,6 +70,10 @@ class OutputSingleLayerOperation : public NodeOperation {
{
return eCompositorPriority::Low;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
/* extra info for OpenEXR layers */
@@ -86,7 +90,7 @@ struct OutputOpenExrLayer {
};
/* Writes inputs into OpenEXR multilayer channels. */
-class OutputOpenExrMultiLayerOperation : public NodeOperation {
+class OutputOpenExrMultiLayerOperation : public MultiThreadedOperation {
protected:
const Scene *m_scene;
const RenderData *m_rd;
@@ -122,6 +126,10 @@ class OutputOpenExrMultiLayerOperation : public NodeOperation {
{
return eCompositorPriority::Low;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
void add_exr_channels(void *exrhandle,
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cc b/source/blender/compositor/operations/COM_SetColorOperation.cc
index bfe735aab15..dbe45fa60db 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cc
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cc
@@ -24,7 +24,6 @@ SetColorOperation::SetColorOperation()
{
this->addOutputSocket(DataType::Color);
flags.is_set_operation = true;
- flags.is_fullframe_operation = true;
}
void SetColorOperation::executePixelSampled(float output[4],
@@ -42,13 +41,4 @@ void SetColorOperation::determineResolution(unsigned int resolution[2],
resolution[1] = preferredResolution[1];
}
-void SetColorOperation::update_memory_buffer(MemoryBuffer *output,
- const rcti &area,
- Span<MemoryBuffer *> UNUSED(inputs))
-{
- BLI_assert(output->is_a_single_elem());
- float *out_elem = output->get_elem(area.xmin, area.ymin);
- copy_v4_v4(out_elem, m_color);
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.h b/source/blender/compositor/operations/COM_SetColorOperation.h
index f4c0948ee1b..f546d5e7668 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.h
+++ b/source/blender/compositor/operations/COM_SetColorOperation.h
@@ -85,10 +85,6 @@ class SetColorOperation : public ConstantOperation {
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) 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_SetValueOperation.cc b/source/blender/compositor/operations/COM_SetValueOperation.cc
index c12fb106afd..ef43cf64653 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cc
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cc
@@ -24,7 +24,6 @@ SetValueOperation::SetValueOperation()
{
this->addOutputSocket(DataType::Value);
flags.is_set_operation = true;
- flags.is_fullframe_operation = true;
}
void SetValueOperation::executePixelSampled(float output[4],
@@ -42,13 +41,4 @@ void SetValueOperation::determineResolution(unsigned int resolution[2],
resolution[1] = preferredResolution[1];
}
-void SetValueOperation::update_memory_buffer(MemoryBuffer *output,
- const rcti &area,
- Span<MemoryBuffer *> UNUSED(inputs))
-{
- BLI_assert(output->is_a_single_elem());
- float *out_elem = output->get_elem(area.xmin, area.ymin);
- *out_elem = m_value;
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.h b/source/blender/compositor/operations/COM_SetValueOperation.h
index f18d44d9554..726624c1c6a 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.h
+++ b/source/blender/compositor/operations/COM_SetValueOperation.h
@@ -56,9 +56,6 @@ class SetValueOperation : public ConstantOperation {
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) 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_SplitOperation.cc b/source/blender/compositor/operations/COM_SplitOperation.cc
index a4754de370d..d18ed3b8e14 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cc
+++ b/source/blender/compositor/operations/COM_SplitOperation.cc
@@ -79,4 +79,17 @@ void SplitOperation::determineResolution(unsigned int resolution[2],
NodeOperation::determineResolution(resolution, preferredResolution);
}
+void SplitOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const int percent = this->m_xSplit ? this->m_splitPercentage * this->getWidth() / 100.0f :
+ this->m_splitPercentage * this->getHeight() / 100.0f;
+ const size_t elem_bytes = COM_data_type_bytes_len(getOutputSocket()->getDataType());
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const bool is_image1 = this->m_xSplit ? it.x > percent : it.y > percent;
+ memcpy(it.out, it.in(is_image1 ? 0 : 1), elem_bytes);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SplitOperation.h b/source/blender/compositor/operations/COM_SplitOperation.h
index 09e48821dd0..2d09d2a07dc 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.h
+++ b/source/blender/compositor/operations/COM_SplitOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class SplitOperation : public NodeOperation {
+class SplitOperation : public MultiThreadedOperation {
private:
SocketReader *m_image1Input;
SocketReader *m_image2Input;
@@ -45,6 +45,10 @@ class SplitOperation : public NodeOperation {
{
this->m_xSplit = xsplit;
}
+
+ 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_SunBeamsOperation.cc b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
index bd82b6397ad..ad96e3a02ba 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cc
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
@@ -30,7 +30,7 @@ SunBeamsOperation::SunBeamsOperation()
this->flags.complex = true;
}
-void SunBeamsOperation::initExecution()
+void SunBeamsOperation::calc_rays_common_data()
{
/* convert to pixels */
this->m_source_px[0] = this->m_data.source[0] * this->getWidth();
@@ -38,6 +38,11 @@ void SunBeamsOperation::initExecution()
this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight());
}
+void SunBeamsOperation::initExecution()
+{
+ calc_rays_common_data();
+}
+
/**
* Defines a line accumulator for a specific sector,
* given by the four matrix entries that rotate from buffer space into the sector
@@ -140,7 +145,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f;
- float *iter = input->getBuffer() + COM_DATA_TYPE_COLOR_CHANNELS * (x + input->getWidth() * y);
+ float *iter = input->getBuffer() + input->get_coords_offset(x, y);
return iter;
}
@@ -159,7 +164,6 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
float dist_max)
{
const rcti &rect = input->get_rect();
- int buffer_width = input->getWidth();
int x, y, num;
float v, dv;
float falloff_factor;
@@ -168,9 +172,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
zero_v4(output);
if ((int)(co[0] - source[0]) == 0 && (int)(co[1] - source[1]) == 0) {
- copy_v4_v4(output,
- input->getBuffer() + COM_DATA_TYPE_COLOR_CHANNELS *
- ((int)source[0] + input->getWidth() * (int)source[1]));
+ copy_v4_v4(output, input->get_elem(source[0], source[1]));
return;
}
@@ -210,7 +212,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
/* decrement u */
x -= fxu;
y -= fyu;
- buffer -= (fxu + fyu * buffer_width) * COM_DATA_TYPE_COLOR_CHANNELS;
+ buffer -= fxu * input->elem_stride + fyu * input->row_stride;
/* decrement v (in steps of dv < 1) */
v_local -= dv;
@@ -219,7 +221,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
x -= fxv;
y -= fyv;
- buffer -= (fxv + fyv * buffer_width) * COM_DATA_TYPE_COLOR_CHANNELS;
+ buffer -= fxv * input->elem_stride + fyv * input->row_stride;
}
}
@@ -356,4 +358,39 @@ bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input,
return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output);
}
+void SunBeamsOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ BLI_assert(input_idx == 0);
+ UNUSED_VARS(input_idx);
+ calc_rays_common_data();
+
+ r_input_area = output_area;
+ /* Enlarges the rect by moving each corner toward the source.
+ * This is the maximum distance that pixels can influence each other
+ * and gives a rect that contains all possible accumulated pixels. */
+ calc_ray_shift(&r_input_area, output_area.xmin, output_area.ymin, m_source_px, m_ray_length_px);
+ calc_ray_shift(&r_input_area, output_area.xmin, output_area.ymax, m_source_px, m_ray_length_px);
+ calc_ray_shift(&r_input_area, output_area.xmax, output_area.ymin, m_source_px, m_ray_length_px);
+ calc_ray_shift(&r_input_area, output_area.xmax, output_area.ymax, m_source_px, m_ray_length_px);
+}
+
+void SunBeamsOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ MemoryBuffer *input = inputs[0];
+ float coords[2];
+ for (int y = area.ymin; y < area.ymax; y++) {
+ coords[1] = y;
+ float *out_elem = output->get_elem(area.xmin, y);
+ for (int x = area.xmin; x < area.xmax; x++) {
+ coords[0] = x;
+ accumulate_line(input, out_elem, coords, m_source_px, 0.0f, m_ray_length_px);
+ out_elem += output->elem_stride;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.h b/source/blender/compositor/operations/COM_SunBeamsOperation.h
index d3725021cde..71fc04453fe 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.h
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.h
@@ -17,11 +17,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class SunBeamsOperation : public NodeOperation {
+class SunBeamsOperation : public MultiThreadedOperation {
public:
SunBeamsOperation();
@@ -40,6 +40,14 @@ class SunBeamsOperation : public NodeOperation {
m_data = data;
}
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
+
+ private:
+ void calc_rays_common_data();
+
private:
NodeSunBeams m_data;
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc
index 6bfacb0c75d..20da468eeb1 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cc
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cc
@@ -17,6 +17,8 @@
*/
#include "COM_TonemapOperation.h"
+#include "COM_ExecutionSystem.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -153,4 +155,126 @@ void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
/* pass */
}
+void TonemapOperation::get_area_of_interest(const int input_idx,
+ const rcti &UNUSED(output_area),
+ rcti &r_input_area)
+{
+ BLI_assert(input_idx == 0);
+ NodeOperation *operation = getInputOperation(input_idx);
+ r_input_area.xmin = 0;
+ r_input_area.ymin = 0;
+ r_input_area.xmax = operation->getWidth();
+ r_input_area.ymax = operation->getHeight();
+}
+
+struct Luminance {
+ float sum;
+ float color_sum[3];
+ float log_sum;
+ float min;
+ float max;
+ int num_pixels;
+};
+
+static Luminance calc_area_luminance(const MemoryBuffer *input, const rcti &area)
+{
+ Luminance lum = {0};
+ for (const float *elem : input->get_buffer_area(area)) {
+ const float lu = IMB_colormanagement_get_luminance(elem);
+ lum.sum += lu;
+ add_v3_v3(lum.color_sum, elem);
+ lum.log_sum += logf(MAX2(lu, 0.0f) + 1e-5f);
+ lum.max = MAX2(lu, lum.max);
+ lum.min = MIN2(lu, lum.min);
+ lum.num_pixels++;
+ }
+ return lum;
+}
+
+void TonemapOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),
+ const rcti &UNUSED(area),
+ Span<MemoryBuffer *> inputs)
+{
+ if (this->m_cachedInstance == nullptr) {
+ Luminance lum = {0};
+ const MemoryBuffer *input = inputs[0];
+ exec_system_->execute_work<Luminance>(
+ input->get_rect(),
+ [=](const rcti &split) { return calc_area_luminance(input, split); },
+ lum,
+ [](Luminance &join, const Luminance &chunk) {
+ join.sum += chunk.sum;
+ add_v3_v3(join.color_sum, chunk.color_sum);
+ join.log_sum += chunk.log_sum;
+ join.max = MAX2(join.max, chunk.max);
+ join.min = MIN2(join.min, chunk.min);
+ join.num_pixels += chunk.num_pixels;
+ });
+
+ AvgLogLum *avg = new AvgLogLum();
+ avg->lav = lum.sum / lum.num_pixels;
+ mul_v3_v3fl(avg->cav, lum.color_sum, 1.0f / lum.num_pixels);
+ const float max_log = log((double)lum.max + 1e-5);
+ const float min_log = log((double)lum.min + 1e-5);
+ const float avg_log = lum.log_sum / lum.num_pixels;
+ avg->auto_key = (max_log > min_log) ? ((max_log - avg_log) / (max_log - min_log)) : 1.0f;
+ const float al = exp((double)avg_log);
+ avg->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al);
+ avg->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma);
+ this->m_cachedInstance = avg;
+ }
+}
+
+void TonemapOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ AvgLogLum *avg = m_cachedInstance;
+ const float igm = avg->igm;
+ const float offset = this->m_data->offset;
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ copy_v4_v4(it.out, it.in(0));
+ mul_v3_fl(it.out, avg->al);
+ float dr = it.out[0] + offset;
+ float dg = it.out[1] + offset;
+ float db = it.out[2] + offset;
+ it.out[0] /= ((dr == 0.0f) ? 1.0f : dr);
+ it.out[1] /= ((dg == 0.0f) ? 1.0f : dg);
+ it.out[2] /= ((db == 0.0f) ? 1.0f : db);
+ if (igm != 0.0f) {
+ it.out[0] = powf(MAX2(it.out[0], 0.0f), igm);
+ it.out[1] = powf(MAX2(it.out[1], 0.0f), igm);
+ it.out[2] = powf(MAX2(it.out[2], 0.0f), igm);
+ }
+ }
+}
+
+void PhotoreceptorTonemapOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ AvgLogLum *avg = m_cachedInstance;
+ NodeTonemap *ntm = this->m_data;
+ const float f = expf(-this->m_data->f);
+ const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
+ const float ic = 1.0f - ntm->c;
+ const float ia = 1.0f - ntm->a;
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ copy_v4_v4(it.out, it.in(0));
+ const float L = IMB_colormanagement_get_luminance(it.out);
+ float I_l = it.out[0] + ic * (L - it.out[0]);
+ float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
+ float I_a = I_l + ia * (I_g - I_l);
+ it.out[0] /= (it.out[0] + powf(f * I_a, m));
+ I_l = it.out[1] + ic * (L - it.out[1]);
+ I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
+ I_a = I_l + ia * (I_g - I_l);
+ it.out[1] /= (it.out[1] + powf(f * I_a, m));
+ I_l = it.out[2] + ic * (L - it.out[2]);
+ I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
+ I_a = I_l + ia * (I_g - I_l);
+ it.out[2] /= (it.out[2] + powf(f * I_a, m));
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h
index 7ecb179504d..56b57730ec1 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.h
+++ b/source/blender/compositor/operations/COM_TonemapOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_node_types.h"
namespace blender::compositor {
@@ -39,7 +39,7 @@ typedef struct AvgLogLum {
* \brief base class of tonemap, implementing the simple tonemap
* \ingroup operation
*/
-class TonemapOperation : public NodeOperation {
+class TonemapOperation : public MultiThreadedOperation {
protected:
/**
* \brief Cached reference to the reader
@@ -85,6 +85,14 @@ class TonemapOperation : 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_started(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+ virtual void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
/**
@@ -99,6 +107,10 @@ class PhotoreceptorTonemapOperation : public TonemapOperation {
* The inner loop of this operation.
*/
void executePixel(float output[4], int x, int y, void *data) 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_TrackPositionOperation.cc b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
index 993410e3e84..0f4be16a620 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cc
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
@@ -42,14 +42,24 @@ TrackPositionOperation::TrackPositionOperation()
this->m_relativeFrame = 0;
this->m_speed_output = false;
flags.is_set_operation = true;
+ is_track_position_calculated_ = false;
}
void TrackPositionOperation::initExecution()
{
+ if (!is_track_position_calculated_) {
+ calc_track_position();
+ }
+}
+
+void TrackPositionOperation::calc_track_position()
+{
+ is_track_position_calculated_ = true;
MovieTracking *tracking = nullptr;
MovieClipUser user = {0};
MovieTrackingObject *object;
+ track_position_ = 0;
zero_v2(this->m_markerPos);
zero_v2(this->m_relativePos);
@@ -114,6 +124,14 @@ void TrackPositionOperation::initExecution()
}
}
}
+
+ track_position_ = this->m_markerPos[this->m_axis] - this->m_relativePos[this->m_axis];
+ if (this->m_axis == 0) {
+ track_position_ *= this->m_width;
+ }
+ else {
+ track_position_ *= this->m_height;
+ }
}
void TrackPositionOperation::executePixelSampled(float output[4],
@@ -131,6 +149,14 @@ void TrackPositionOperation::executePixelSampled(float output[4],
}
}
+const float *TrackPositionOperation::get_constant_elem()
+{
+ if (!is_track_position_calculated_) {
+ calc_track_position();
+ }
+ return &track_position_;
+}
+
void TrackPositionOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
{
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.h b/source/blender/compositor/operations/COM_TrackPositionOperation.h
index b0b0a123bd6..f716bd97737 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.h
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.h
@@ -20,7 +20,7 @@
#include <string.h>
-#include "COM_NodeOperation.h"
+#include "COM_ConstantOperation.h"
#include "DNA_movieclip_types.h"
#include "DNA_tracking_types.h"
@@ -33,7 +33,7 @@ namespace blender::compositor {
/**
* Class with implementation of green screen gradient rasterization
*/
-class TrackPositionOperation : public NodeOperation {
+class TrackPositionOperation : public ConstantOperation {
protected:
MovieClip *m_movieClip;
int m_framenumber;
@@ -47,6 +47,8 @@ class TrackPositionOperation : public NodeOperation {
int m_width, m_height;
float m_markerPos[2];
float m_relativePos[2];
+ float track_position_;
+ bool is_track_position_calculated_;
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -93,6 +95,11 @@ class TrackPositionOperation : public NodeOperation {
void initExecution() override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ const float *get_constant_elem() override;
+
+ private:
+ void calc_track_position();
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cc b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
index 9d53ed5d8ee..c2087fd071e 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.cc
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
@@ -53,4 +53,14 @@ void VectorCurveOperation::deinitExecution()
this->m_inputProgram = nullptr;
}
+void VectorCurveOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ CurveMapping *curve_map = this->m_curveMapping;
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ BKE_curvemapping_evaluate_premulRGBF(curve_map, it.out, it.in(0));
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.h b/source/blender/compositor/operations/COM_VectorCurveOperation.h
index 8cbb80e27c7..27b3ad69e17 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.h
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.h
@@ -47,6 +47,10 @@ class VectorCurveOperation : public CurveBaseOperation {
* Deinitialize the execution
*/
void deinitExecution() 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_WrapOperation.cc b/source/blender/compositor/operations/COM_WrapOperation.cc
index d0d2fcac3ac..888602114cc 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.cc
+++ b/source/blender/compositor/operations/COM_WrapOperation.cc
@@ -57,20 +57,20 @@ void WrapOperation::executePixelSampled(float output[4], float x, float y, Pixel
MemoryBufferExtend extend_x = MemoryBufferExtend::Clip, extend_y = MemoryBufferExtend::Clip;
switch (m_wrappingType) {
case CMP_NODE_WRAP_NONE:
- // Intentionally empty, originalXPos and originalYPos have been set before
+ /* Intentionally empty, originalXPos and originalYPos have been set before. */
break;
case CMP_NODE_WRAP_X:
- // wrap only on the x-axis
+ /* Wrap only on the x-axis. */
nx = this->getWrappedOriginalXPos(x);
extend_x = MemoryBufferExtend::Repeat;
break;
case CMP_NODE_WRAP_Y:
- // wrap only on the y-axis
+ /* Wrap only on the y-axis. */
ny = this->getWrappedOriginalYPos(y);
extend_y = MemoryBufferExtend::Repeat;
break;
case CMP_NODE_WRAP_XY:
- // wrap on both
+ /* Wrap on both. */
nx = this->getWrappedOriginalXPos(x);
ny = this->getWrappedOriginalYPos(y);
extend_x = MemoryBufferExtend::Repeat;
@@ -92,7 +92,7 @@ bool WrapOperation::determineDependingAreaOfInterest(rcti *input,
newInput.ymax = input->ymax;
if (ELEM(m_wrappingType, CMP_NODE_WRAP_X, CMP_NODE_WRAP_XY)) {
- // wrap only on the x-axis if tile is wrapping
+ /* Wrap only on the x-axis if tile is wrapping. */
newInput.xmin = getWrappedOriginalXPos(input->xmin);
newInput.xmax = roundf(getWrappedOriginalXPos(input->xmax));
if (newInput.xmin >= newInput.xmax) {
@@ -101,7 +101,7 @@ bool WrapOperation::determineDependingAreaOfInterest(rcti *input,
}
}
if (ELEM(m_wrappingType, CMP_NODE_WRAP_Y, CMP_NODE_WRAP_XY)) {
- // wrap only on the y-axis if tile is wrapping
+ /* Wrap only on the y-axis if tile is wrapping. */
newInput.ymin = getWrappedOriginalYPos(input->ymin);
newInput.ymax = roundf(getWrappedOriginalYPos(input->ymax));
if (newInput.ymin >= newInput.ymax) {
diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cc b/source/blender/compositor/operations/COM_ZCombineOperation.cc
index 9d3ca7e736e..7050c3b2d83 100644
--- a/source/blender/compositor/operations/COM_ZCombineOperation.cc
+++ b/source/blender/compositor/operations/COM_ZCombineOperation.cc
@@ -33,6 +33,7 @@ ZCombineOperation::ZCombineOperation()
this->m_depth1Reader = nullptr;
this->m_image2Reader = nullptr;
this->m_depth2Reader = nullptr;
+ this->flags.can_be_constant = true;
}
void ZCombineOperation::initExecution()
@@ -60,6 +61,19 @@ void ZCombineOperation::executePixelSampled(float output[4],
this->m_image2Reader->readSampled(output, x, y, sampler);
}
}
+
+void ZCombineOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float depth1 = *it.in(1);
+ const float depth2 = *it.in(3);
+ const float *color = (depth1 < depth2) ? it.in(0) : it.in(2);
+ copy_v4_v4(it.out, color);
+ }
+}
+
void ZCombineAlphaOperation::executePixelSampled(float output[4],
float x,
float y,
@@ -88,6 +102,32 @@ void ZCombineAlphaOperation::executePixelSampled(float output[4],
output[3] = MAX2(color1[3], color2[3]);
}
+void ZCombineAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float depth1 = *it.in(1);
+ const float depth2 = *it.in(3);
+ const float *color1;
+ const float *color2;
+ if (depth1 <= depth2) {
+ color1 = it.in(0);
+ color2 = it.in(2);
+ }
+ else {
+ color1 = it.in(2);
+ color2 = it.in(0);
+ }
+ const float fac = color1[3];
+ const float ifac = 1.0f - fac;
+ it.out[0] = fac * color1[0] + ifac * color2[0];
+ it.out[1] = fac * color1[1] + ifac * color2[1];
+ it.out[2] = fac * color1[2] + ifac * color2[2];
+ it.out[3] = MAX2(color1[3], color2[3]);
+ }
+}
+
void ZCombineOperation::deinitExecution()
{
this->m_image1Reader = nullptr;
@@ -132,6 +172,18 @@ void ZCombineMaskOperation::executePixelSampled(float output[4],
interp_v4_v4v4(output, color1, color2, 1.0f - mask[0]);
}
+void ZCombineMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float mask = *it.in(0);
+ const float *color1 = it.in(1);
+ const float *color2 = it.in(2);
+ interp_v4_v4v4(it.out, color1, color2, 1.0f - mask);
+ }
+}
+
void ZCombineMaskAlphaOperation::executePixelSampled(float output[4],
float x,
float y,
@@ -154,6 +206,24 @@ void ZCombineMaskAlphaOperation::executePixelSampled(float output[4],
output[3] = MAX2(color1[3], color2[3]);
}
+void ZCombineMaskAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ const float mask = *it.in(0);
+ const float *color1 = it.in(1);
+ const float *color2 = it.in(2);
+ const float fac = (1.0f - mask) * (1.0f - color1[3]) + mask * color2[3];
+ const float mfac = 1.0f - fac;
+
+ it.out[0] = color1[0] * mfac + color2[0] * fac;
+ it.out[1] = color1[1] * mfac + color2[1] * fac;
+ it.out[2] = color1[2] * mfac + color2[2] * fac;
+ it.out[3] = MAX2(color1[3], color2[3]);
+ }
+}
+
void ZCombineMaskOperation::deinitExecution()
{
this->m_image1Reader = nullptr;
diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.h b/source/blender/compositor/operations/COM_ZCombineOperation.h
index d0b1aee7310..acd60b6c866 100644
--- a/source/blender/compositor/operations/COM_ZCombineOperation.h
+++ b/source/blender/compositor/operations/COM_ZCombineOperation.h
@@ -26,7 +26,7 @@ namespace blender::compositor {
* this program converts an input color to an output value.
* it assumes we are in sRGB color space.
*/
-class ZCombineOperation : public NodeOperation {
+class ZCombineOperation : public MultiThreadedOperation {
protected:
SocketReader *m_image1Reader;
SocketReader *m_depth1Reader;
@@ -46,13 +46,21 @@ class ZCombineOperation : public NodeOperation {
* The inner loop of this operation.
*/
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 ZCombineAlphaOperation : public ZCombineOperation {
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 ZCombineMaskOperation : public NodeOperation {
+class ZCombineMaskOperation : public MultiThreadedOperation {
protected:
SocketReader *m_maskReader;
SocketReader *m_image1Reader;
@@ -64,9 +72,17 @@ class ZCombineMaskOperation : public NodeOperation {
void initExecution() override;
void deinitExecution() 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;
};
class ZCombineMaskAlphaOperation : public ZCombineMaskOperation {
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;
};
} // namespace blender::compositor