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.txt7
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.cc22
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.h7
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.cc191
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.h64
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc43
-rw-r--r--source/blender/compositor/intern/COM_Debug.h4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionModel.cc6
-rw-r--r--source/blender/compositor/intern/COM_ExecutionModel.h9
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc74
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h6
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.cc100
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.h13
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc12
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h2
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedOperation.cc5
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedOperation.h3
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedRowOperation.cc50
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedRowOperation.h60
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc26
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h36
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc39
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.h8
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cc4
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.h2
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc18
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc18
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.cc81
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_ColorExposureOperation.cc14
-rw-r--r--source/blender/compositor/operations/COM_ColorExposureOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_ConstantOperation.cc28
-rw-r--r--source/blender/compositor/operations/COM_ConstantOperation.h36
-rw-r--r--source/blender/compositor/operations/COM_GammaOperation.cc15
-rw-r--r--source/blender/compositor/operations/COM_GammaOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.cc1
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cc3
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cc3
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.cc6
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.h35
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cc4
48 files changed, 913 insertions, 206 deletions
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index ac59d832013..20b56ceb55f 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -59,6 +59,8 @@ set(SRC
intern/COM_ChunkOrderHotspot.h
intern/COM_CompositorContext.cc
intern/COM_CompositorContext.h
+ intern/COM_ConstantFolder.cc
+ intern/COM_ConstantFolder.h
intern/COM_Converter.cc
intern/COM_Converter.h
intern/COM_Debug.cc
@@ -66,6 +68,7 @@ set(SRC
intern/COM_Device.cc
intern/COM_Device.h
intern/COM_Enums.cc
+ intern/COM_Enums.h
intern/COM_ExecutionGroup.cc
intern/COM_ExecutionGroup.h
intern/COM_ExecutionModel.cc
@@ -82,6 +85,8 @@ set(SRC
intern/COM_MetaData.h
intern/COM_MultiThreadedOperation.cc
intern/COM_MultiThreadedOperation.h
+ intern/COM_MultiThreadedRowOperation.cc
+ intern/COM_MultiThreadedRowOperation.h
intern/COM_Node.cc
intern/COM_Node.h
intern/COM_NodeConverter.cc
@@ -442,6 +447,8 @@ set(SRC
operations/COM_BrightnessOperation.h
operations/COM_ColorCorrectionOperation.cc
operations/COM_ColorCorrectionOperation.h
+ operations/COM_ConstantOperation.cc
+ operations/COM_ConstantOperation.h
operations/COM_GammaOperation.cc
operations/COM_GammaOperation.h
operations/COM_MixOperation.cc
diff --git a/source/blender/compositor/intern/COM_BufferOperation.cc b/source/blender/compositor/intern/COM_BufferOperation.cc
index 8464d01801f..90c97f2a9c7 100644
--- a/source/blender/compositor/intern/COM_BufferOperation.cc
+++ b/source/blender/compositor/intern/COM_BufferOperation.cc
@@ -23,6 +23,7 @@ namespace blender::compositor {
BufferOperation::BufferOperation(MemoryBuffer *buffer, DataType data_type)
{
buffer_ = buffer;
+ inflated_buffer_ = nullptr;
/* TODO: Implement a MemoryBuffer get_size() method returning a Size2d type. Shorten following
* code to: set_resolution(buffer.get_size()) */
unsigned int resolution[2];
@@ -30,11 +31,30 @@ BufferOperation::BufferOperation(MemoryBuffer *buffer, DataType data_type)
resolution[1] = buffer->getHeight();
setResolution(resolution);
addOutputSocket(data_type);
+ flags.is_constant_operation = buffer_->is_a_single_elem();
+}
+
+const float *BufferOperation::get_constant_elem()
+{
+ BLI_assert(buffer_->is_a_single_elem());
+ return buffer_->getBuffer();
}
void *BufferOperation::initializeTileData(rcti * /*rect*/)
{
- return buffer_;
+ if (buffer_->is_a_single_elem() == false) {
+ return buffer_;
+ }
+
+ if (!inflated_buffer_) {
+ inflated_buffer_ = buffer_->inflate();
+ }
+ return inflated_buffer_;
+}
+
+void BufferOperation::deinitExecution()
+{
+ delete inflated_buffer_;
}
void BufferOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
diff --git a/source/blender/compositor/intern/COM_BufferOperation.h b/source/blender/compositor/intern/COM_BufferOperation.h
index f87cd4db94e..705264c37b7 100644
--- a/source/blender/compositor/intern/COM_BufferOperation.h
+++ b/source/blender/compositor/intern/COM_BufferOperation.h
@@ -18,18 +18,21 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_ConstantOperation.h"
namespace blender::compositor {
-class BufferOperation : public NodeOperation {
+class BufferOperation : public ConstantOperation {
private:
MemoryBuffer *buffer_;
+ MemoryBuffer *inflated_buffer_;
public:
BufferOperation(MemoryBuffer *buffer, DataType data_type);
+ const float *get_constant_elem() override;
void *initializeTileData(rcti *rect) 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
new file mode 100644
index 00000000000..a9427013f87
--- /dev/null
+++ b/source/blender/compositor/intern/COM_ConstantFolder.cc
@@ -0,0 +1,191 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "BLI_rect.h"
+
+#include "COM_ConstantFolder.h"
+#include "COM_ConstantOperation.h"
+#include "COM_SetColorOperation.h"
+#include "COM_SetValueOperation.h"
+#include "COM_SetVectorOperation.h"
+#include "COM_WorkScheduler.h"
+
+namespace blender::compositor {
+
+using Link = NodeOperationBuilder::Link;
+
+/**
+ * \param operations_builder: Contains all operations to fold.
+ * \param exec_system: Execution system.
+ */
+ConstantFolder::ConstantFolder(NodeOperationBuilder &operations_builder)
+ : operations_builder_(operations_builder)
+{
+ BLI_rcti_init(&max_area_, INT_MIN, INT_MAX, INT_MIN, INT_MAX);
+ BLI_rcti_init(&first_elem_area_, 0, 1, 0, 1);
+}
+
+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) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+static Vector<NodeOperation *> find_constant_foldable_operations(Span<NodeOperation *> operations)
+{
+ Vector<NodeOperation *> foldable_ops;
+ for (NodeOperation *op : operations) {
+ if (is_constant_foldable(op)) {
+ foldable_ops.append(op);
+ }
+ }
+ return foldable_ops;
+}
+
+static ConstantOperation *create_constant_operation(DataType data_type, const float *constant_elem)
+{
+ switch (data_type) {
+ case DataType::Color: {
+ SetColorOperation *color_op = new SetColorOperation();
+ color_op->setChannels(constant_elem);
+ return color_op;
+ }
+ case DataType::Vector: {
+ SetVectorOperation *vector_op = new SetVectorOperation();
+ vector_op->setVector(constant_elem);
+ return vector_op;
+ }
+ case DataType::Value: {
+ SetValueOperation *value_op = new SetValueOperation();
+ value_op->setValue(*constant_elem);
+ return value_op;
+ }
+ default: {
+ BLI_assert(!"Non implemented data type");
+ return nullptr;
+ }
+ }
+}
+
+ConstantOperation *ConstantFolder::fold_operation(NodeOperation *operation)
+{
+ const DataType data_type = operation->getOutputSocket()->getDataType();
+ MemoryBuffer fold_buf(data_type, first_elem_area_);
+ Vector<MemoryBuffer *> input_bufs = get_constant_input_buffers(operation);
+ operation->render(&fold_buf, {first_elem_area_}, input_bufs);
+
+ MemoryBuffer *constant_buf = create_constant_buffer(data_type);
+ constant_buf->copy_from(&fold_buf, first_elem_area_);
+ ConstantOperation *constant_op = create_constant_operation(data_type, constant_buf->getBuffer());
+ operations_builder_.replace_operation_with_constant(operation, constant_op);
+ constant_buffers_.add_new(constant_op, constant_buf);
+ return constant_op;
+}
+
+MemoryBuffer *ConstantFolder::create_constant_buffer(const DataType data_type)
+{
+ /* Create a single elem buffer with maximum area possible so readers can read any coordinate
+ * returning always same element. */
+ return new MemoryBuffer(data_type, max_area_, true);
+}
+
+Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation *operation)
+{
+ const int num_inputs = operation->getNumberOfInputSockets();
+ Vector<MemoryBuffer *> inputs_bufs(num_inputs);
+ for (int i = 0; i < num_inputs; i++) {
+ BLI_assert(operation->get_input_operation(i)->get_flags().is_constant_operation);
+ ConstantOperation *constant_op = static_cast<ConstantOperation *>(
+ operation->get_input_operation(i));
+ MemoryBuffer *constant_buf = constant_buffers_.lookup_or_add_cb(constant_op, [=] {
+ MemoryBuffer *buf = create_constant_buffer(constant_op->getOutputSocket()->getDataType());
+ constant_op->render(buf, {first_elem_area_}, {});
+ return buf;
+ });
+ inputs_bufs[i] = constant_buf;
+ }
+ return inputs_bufs;
+}
+
+/** Returns constant operations resulted from folded operations. */
+Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperation *> operations)
+{
+ Vector<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations);
+ if (foldable_ops.size() == 0) {
+ return Vector<ConstantOperation *>();
+ }
+
+ Vector<ConstantOperation *> new_folds;
+ for (NodeOperation *op : foldable_ops) {
+ ConstantOperation *constant_op = fold_operation(op);
+ new_folds.append(constant_op);
+ }
+ return new_folds;
+}
+
+/**
+ * Evaluate operations with constant elements into primitive constant operations.
+ */
+int ConstantFolder::fold_operations()
+{
+ WorkScheduler::start(operations_builder_.context());
+ Vector<ConstantOperation *> last_folds = try_fold_operations(
+ operations_builder_.get_operations());
+ int folds_count = last_folds.size();
+ while (last_folds.size() > 0) {
+ Vector<NodeOperation *> ops_to_fold;
+ for (ConstantOperation *fold : last_folds) {
+ get_operation_output_operations(fold, ops_to_fold);
+ }
+ last_folds = try_fold_operations(ops_to_fold);
+ folds_count += last_folds.size();
+ }
+ WorkScheduler::stop();
+
+ delete_constant_buffers();
+
+ return folds_count;
+}
+
+void ConstantFolder::delete_constant_buffers()
+{
+ for (MemoryBuffer *buf : constant_buffers_.values()) {
+ delete buf;
+ }
+ constant_buffers_.clear();
+}
+
+void ConstantFolder::get_operation_output_operations(NodeOperation *operation,
+ Vector<NodeOperation *> &r_outputs)
+{
+ const Vector<Link> &links = operations_builder_.get_links();
+ for (const Link &link : links) {
+ if (&link.from()->getOperation() == operation) {
+ r_outputs.append(&link.to()->getOperation());
+ }
+ }
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.h b/source/blender/compositor/intern/COM_ConstantFolder.h
new file mode 100644
index 00000000000..2432e859a5a
--- /dev/null
+++ b/source/blender/compositor/intern/COM_ConstantFolder.h
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "BLI_map.hh"
+#include "BLI_set.hh"
+#include "BLI_vector.hh"
+
+#include "COM_NodeOperationBuilder.h"
+#include "COM_defines.h"
+
+namespace blender::compositor {
+
+class NodeOperation;
+class ConstantOperation;
+class MemoryBuffer;
+
+/**
+ * Evaluates all operations with constant elements into primitive constant operations
+ * (Value/Vector/Color).
+ */
+class ConstantFolder {
+ private:
+ NodeOperationBuilder &operations_builder_;
+
+ /** Constant operations buffers. */
+ Map<ConstantOperation *, MemoryBuffer *> constant_buffers_;
+
+ rcti max_area_;
+ rcti first_elem_area_;
+
+ public:
+ ConstantFolder(NodeOperationBuilder &operations_builder);
+ int fold_operations();
+
+ private:
+ Vector<ConstantOperation *> try_fold_operations(Span<NodeOperation *> operations);
+ ConstantOperation *fold_operation(NodeOperation *operation);
+
+ MemoryBuffer *create_constant_buffer(DataType data_type);
+ Vector<MemoryBuffer *> get_constant_input_buffers(NodeOperation *operation);
+ void delete_constant_buffers();
+
+ void get_operation_output_operations(NodeOperation *operation,
+ Vector<NodeOperation *> &r_outputs);
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 4cf7e09a7d8..abef4517b3e 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -37,6 +37,7 @@ extern "C" {
#include "COM_Node.h"
#include "COM_ReadBufferOperation.h"
+#include "COM_SetValueOperation.h"
#include "COM_ViewerOperation.h"
#include "COM_WriteBufferOperation.h"
@@ -49,6 +50,15 @@ std::string DebugInfo::m_current_node_name;
std::string DebugInfo::m_current_op_name;
DebugInfo::GroupStateMap DebugInfo::m_group_states;
+static std::string operation_class_name(NodeOperation *op)
+{
+ std::string full_name = typeid(*op).name();
+ /* Remove name-spaces. */
+ size_t pos = full_name.find_last_of(':');
+ BLI_assert(pos != std::string::npos);
+ return full_name.substr(pos + 1);
+}
+
std::string DebugInfo::node_name(const Node *node)
{
NodeNameMap::const_iterator it = m_node_names.find(node);
@@ -135,15 +145,23 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|");
}
+ if (COM_GRAPHVIZ_SHOW_NODE_NAME) {
+ std::string op_node_name = operation->get_name();
+ if (!op_node_name.empty()) {
+ len += snprintf(
+ str + len, maxlen > len ? maxlen - len : 0, "%s\\n", (op_node_name + " Node").c_str());
+ }
+ }
+
len += snprintf(str + len,
maxlen > len ? maxlen - len : 0,
- "%s\\n(%s)",
- m_op_names[operation].c_str(),
- typeid(*operation).name());
+ "%s\\n",
+ operation_class_name(operation).c_str());
len += snprintf(str + len,
maxlen > len ? maxlen - len : 0,
- " (%u,%u)",
+ "#%d (%u,%u)",
+ operation->get_id(),
operation->getWidth(),
operation->getHeight());
@@ -159,7 +177,13 @@ 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:
- len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value");
+ if (typeid(*operation) == typeid(SetValueOperation)) {
+ const float value = ((SetValueOperation *)operation)->getValue();
+ 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:
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector");
@@ -401,7 +425,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
return (len < maxlen);
}
-void DebugInfo::graphviz(const ExecutionSystem *system)
+void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
{
if (!COM_EXPORT_GRAPHVIZ) {
return;
@@ -411,7 +435,12 @@ void DebugInfo::graphviz(const ExecutionSystem *system)
char basename[FILE_MAX];
char filename[FILE_MAX];
- BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index);
+ if (name.is_empty()) {
+ BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index);
+ }
+ else {
+ BLI_strncpy(basename, (name + ".dot").c_str(), sizeof(basename));
+ }
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename);
m_file_index++;
diff --git a/source/blender/compositor/intern/COM_Debug.h b/source/blender/compositor/intern/COM_Debug.h
index 0de3a5e39dc..53461e13f48 100644
--- a/source/blender/compositor/intern/COM_Debug.h
+++ b/source/blender/compositor/intern/COM_Debug.h
@@ -28,6 +28,8 @@
namespace blender::compositor {
static constexpr bool COM_EXPORT_GRAPHVIZ = false;
+static constexpr bool COM_GRAPHVIZ_SHOW_NODE_NAME = false;
+
class Node;
class ExecutionSystem;
class ExecutionGroup;
@@ -116,7 +118,7 @@ class DebugInfo {
}
};
- static void graphviz(const ExecutionSystem *system);
+ static void graphviz(const ExecutionSystem *system, StringRefNull name = "");
protected:
static int graphviz_operation(const ExecutionSystem *system,
diff --git a/source/blender/compositor/intern/COM_ExecutionModel.cc b/source/blender/compositor/intern/COM_ExecutionModel.cc
index 4d7f62e091b..b75b277e92c 100644
--- a/source/blender/compositor/intern/COM_ExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_ExecutionModel.cc
@@ -39,10 +39,4 @@ ExecutionModel::ExecutionModel(CompositorContext &context, Span<NodeOperation *>
border_.render_border = &rd->border;
}
-bool ExecutionModel::is_breaked() const
-{
- const bNodeTree *btree = context_.getbNodeTree();
- return btree->test_break(btree->tbh);
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ExecutionModel.h b/source/blender/compositor/intern/COM_ExecutionModel.h
index 9e8466b9282..452861ae4be 100644
--- a/source/blender/compositor/intern/COM_ExecutionModel.h
+++ b/source/blender/compositor/intern/COM_ExecutionModel.h
@@ -67,15 +67,6 @@ class ExecutionModel {
virtual void execute(ExecutionSystem &exec_system) = 0;
- virtual void execute_work(const rcti &UNUSED(work_rect),
- std::function<void(const rcti &split_rect)> UNUSED(work_func))
- {
- BLI_assert(!"Method not supported by current execution model");
- }
-
- protected:
- bool is_breaked() const;
-
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:BaseExecutionModel")
#endif
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index a12ec774032..dfcf76cdd0a 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cc
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -63,8 +63,11 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
this->m_context.setViewSettings(viewSettings);
this->m_context.setDisplaySettings(displaySettings);
+ BLI_mutex_init(&work_mutex_);
+ BLI_condition_init(&work_finished_cond_);
+
{
- NodeOperationBuilder builder(&m_context, editingtree);
+ NodeOperationBuilder builder(&m_context, editingtree, this);
builder.convertToOperations(this);
}
@@ -83,6 +86,9 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
ExecutionSystem::~ExecutionSystem()
{
+ BLI_condition_end(&work_finished_cond_);
+ BLI_mutex_end(&work_mutex_);
+
delete execution_model_;
for (NodeOperation *operation : m_operations) {
@@ -109,10 +115,74 @@ void ExecutionSystem::execute()
execution_model_->execute(*this);
}
+/**
+ * Multi-threadedly execute given work function passing work_rect splits as argument.
+ */
void ExecutionSystem::execute_work(const rcti &work_rect,
std::function<void(const rcti &split_rect)> work_func)
{
- execution_model_->execute_work(work_rect, work_func);
+ if (is_breaked()) {
+ return;
+ }
+
+ /* Split work vertically to maximize continuous memory. */
+ const int work_height = BLI_rcti_size_y(&work_rect);
+ const int num_sub_works = MIN2(WorkScheduler::get_num_cpu_threads(), work_height);
+ const int split_height = num_sub_works == 0 ? 0 : work_height / num_sub_works;
+ int remaining_height = work_height - split_height * num_sub_works;
+
+ Vector<WorkPackage> sub_works(num_sub_works);
+ int sub_work_y = work_rect.ymin;
+ int num_sub_works_finished = 0;
+ for (int i = 0; i < num_sub_works; i++) {
+ int sub_work_height = split_height;
+
+ /* Distribute remaining height between sub-works. */
+ if (remaining_height > 0) {
+ sub_work_height++;
+ remaining_height--;
+ }
+
+ WorkPackage &sub_work = sub_works[i];
+ sub_work.type = eWorkPackageType::CustomFunction;
+ sub_work.execute_fn = [=, &work_func, &work_rect]() {
+ if (is_breaked()) {
+ return;
+ }
+ rcti split_rect;
+ BLI_rcti_init(
+ &split_rect, work_rect.xmin, work_rect.xmax, sub_work_y, sub_work_y + sub_work_height);
+ work_func(split_rect);
+ };
+ sub_work.executed_fn = [&]() {
+ BLI_mutex_lock(&work_mutex_);
+ num_sub_works_finished++;
+ if (num_sub_works_finished == num_sub_works) {
+ BLI_condition_notify_one(&work_finished_cond_);
+ }
+ BLI_mutex_unlock(&work_mutex_);
+ };
+ WorkScheduler::schedule(&sub_work);
+ sub_work_y += sub_work_height;
+ }
+ BLI_assert(sub_work_y == work_rect.ymax);
+
+ WorkScheduler::finish();
+
+ /* Ensure all sub-works finished.
+ * TODO: This a workaround for WorkScheduler::finish() not waiting all works on queue threading
+ * model. Sync code should be removed once it's fixed. */
+ BLI_mutex_lock(&work_mutex_);
+ if (num_sub_works_finished < num_sub_works) {
+ BLI_condition_wait(&work_finished_cond_, &work_mutex_);
+ }
+ BLI_mutex_unlock(&work_mutex_);
+}
+
+bool ExecutionSystem::is_breaked() const
+{
+ const bNodeTree *btree = m_context.getbNodeTree();
+ return btree->test_break(btree->tbh);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index e106209651c..38c3432a8ec 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -150,7 +150,9 @@ class ExecutionSystem {
*/
ExecutionModel *execution_model_;
- private: // methods
+ ThreadMutex work_mutex_;
+ ThreadCondition work_finished_cond_;
+
public:
/**
* \brief Create a new ExecutionSystem and initialize it with the
@@ -199,6 +201,8 @@ class ExecutionSystem {
void execute_work(const rcti &work_rect, std::function<void(const rcti &split_rect)> work_func);
+ bool is_breaked() const;
+
private:
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
index 21075bb7255..3b0a9172871 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
@@ -35,24 +35,13 @@ FullFrameExecutionModel::FullFrameExecutionModel(CompositorContext &context,
Span<NodeOperation *> operations)
: ExecutionModel(context, operations),
active_buffers_(shared_buffers),
- num_operations_finished_(0),
- work_mutex_(),
- work_finished_cond_()
+ num_operations_finished_(0)
{
priorities_.append(eCompositorPriority::High);
if (!context.isFastCalculation()) {
priorities_.append(eCompositorPriority::Medium);
priorities_.append(eCompositorPriority::Low);
}
-
- BLI_mutex_init(&work_mutex_);
- BLI_condition_init(&work_finished_cond_);
-}
-
-FullFrameExecutionModel::~FullFrameExecutionModel()
-{
- BLI_condition_end(&work_finished_cond_);
- BLI_mutex_end(&work_mutex_);
}
void FullFrameExecutionModel::execute(ExecutionSystem &exec_system)
@@ -60,10 +49,10 @@ void FullFrameExecutionModel::execute(ExecutionSystem &exec_system)
const bNodeTree *node_tree = this->context_.getbNodeTree();
node_tree->stats_draw(node_tree->sdh, TIP_("Compositing | Initializing execution"));
- DebugInfo::graphviz(&exec_system);
+ DebugInfo::graphviz(&exec_system, "compositor_prior_rendering");
determine_areas_to_render_and_reads();
- render_operations(exec_system);
+ render_operations();
}
void FullFrameExecutionModel::determine_areas_to_render_and_reads()
@@ -101,20 +90,18 @@ MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op
BLI_rcti_init(&op_rect, 0, op->getWidth(), 0, op->getHeight());
const DataType data_type = op->getOutputSocket(0)->getDataType();
- /* TODO: We should check if the operation is constant instead of is_set_operation. Finding a way
- * to know if an operation is constant has to be implemented yet. */
- const bool is_a_single_elem = op->get_flags().is_set_operation;
+ const bool is_a_single_elem = op->get_flags().is_constant_operation;
return new MemoryBuffer(data_type, op_rect, is_a_single_elem);
}
-void FullFrameExecutionModel::render_operation(NodeOperation *op, ExecutionSystem &exec_system)
+void FullFrameExecutionModel::render_operation(NodeOperation *op)
{
Vector<MemoryBuffer *> input_bufs = get_input_buffers(op);
const bool has_outputs = op->getNumberOfOutputSockets() > 0;
MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr;
Span<rcti> areas = active_buffers_.get_areas_to_render(op);
- op->render(op_buf, areas, input_bufs, exec_system);
+ op->render(op_buf, areas, input_bufs);
active_buffers_.set_rendered_buffer(op, std::unique_ptr<MemoryBuffer>(op_buf));
operation_finished(op);
@@ -123,7 +110,7 @@ void FullFrameExecutionModel::render_operation(NodeOperation *op, ExecutionSyste
/**
* Render output operations in order of priority.
*/
-void FullFrameExecutionModel::render_operations(ExecutionSystem &exec_system)
+void FullFrameExecutionModel::render_operations()
{
const bool is_rendering = context_.isRendering();
@@ -131,8 +118,8 @@ void FullFrameExecutionModel::render_operations(ExecutionSystem &exec_system)
for (eCompositorPriority priority : priorities_) {
for (NodeOperation *op : operations_) {
if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) {
- render_output_dependencies(op, exec_system);
- render_operation(op, exec_system);
+ render_output_dependencies(op);
+ render_operation(op);
}
}
}
@@ -166,14 +153,13 @@ static Vector<NodeOperation *> get_operation_dependencies(NodeOperation *operati
return dependencies;
}
-void FullFrameExecutionModel::render_output_dependencies(NodeOperation *output_op,
- ExecutionSystem &exec_system)
+void FullFrameExecutionModel::render_output_dependencies(NodeOperation *output_op)
{
BLI_assert(output_op->isOutputOperation(context_.isRendering()));
Vector<NodeOperation *> dependencies = get_operation_dependencies(output_op);
for (NodeOperation *op : dependencies) {
if (!active_buffers_.is_operation_rendered(op)) {
- render_operation(op, exec_system);
+ render_operation(op);
}
}
}
@@ -266,70 +252,6 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r
}
}
-/**
- * Multi-threadedly execute given work function passing work_rect splits as argument.
- */
-void FullFrameExecutionModel::execute_work(const rcti &work_rect,
- std::function<void(const rcti &split_rect)> work_func)
-{
- if (is_breaked()) {
- return;
- }
-
- /* Split work vertically to maximize continuous memory. */
- const int work_height = BLI_rcti_size_y(&work_rect);
- const int num_sub_works = MIN2(WorkScheduler::get_num_cpu_threads(), work_height);
- const int split_height = num_sub_works == 0 ? 0 : work_height / num_sub_works;
- int remaining_height = work_height - split_height * num_sub_works;
-
- Vector<WorkPackage> sub_works(num_sub_works);
- int sub_work_y = work_rect.ymin;
- int num_sub_works_finished = 0;
- for (int i = 0; i < num_sub_works; i++) {
- int sub_work_height = split_height;
-
- /* Distribute remaining height between sub-works. */
- if (remaining_height > 0) {
- sub_work_height++;
- remaining_height--;
- }
-
- WorkPackage &sub_work = sub_works[i];
- sub_work.type = eWorkPackageType::CustomFunction;
- sub_work.execute_fn = [=, &work_func, &work_rect]() {
- if (is_breaked()) {
- return;
- }
- rcti split_rect;
- BLI_rcti_init(
- &split_rect, work_rect.xmin, work_rect.xmax, sub_work_y, sub_work_y + sub_work_height);
- work_func(split_rect);
- };
- sub_work.executed_fn = [&]() {
- BLI_mutex_lock(&work_mutex_);
- num_sub_works_finished++;
- if (num_sub_works_finished == num_sub_works) {
- BLI_condition_notify_one(&work_finished_cond_);
- }
- BLI_mutex_unlock(&work_mutex_);
- };
- WorkScheduler::schedule(&sub_work);
- sub_work_y += sub_work_height;
- }
- BLI_assert(sub_work_y == work_rect.ymax);
-
- WorkScheduler::finish();
-
- /* Ensure all sub-works finished.
- * TODO: This a workaround for WorkScheduler::finish() not waiting all works on queue threading
- * model. Sync code should be removed once it's fixed. */
- BLI_mutex_lock(&work_mutex_);
- if (num_sub_works_finished < num_sub_works) {
- BLI_condition_wait(&work_finished_cond_, &work_mutex_);
- }
- BLI_mutex_unlock(&work_mutex_);
-}
-
void FullFrameExecutionModel::operation_finished(NodeOperation *operation)
{
/* Report inputs reads so that buffers may be freed/reused. */
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
index e68ad93b407..f75d4f1afdc 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
@@ -50,27 +50,20 @@ class FullFrameExecutionModel : public ExecutionModel {
*/
Vector<eCompositorPriority> priorities_;
- ThreadMutex work_mutex_;
- ThreadCondition work_finished_cond_;
-
public:
FullFrameExecutionModel(CompositorContext &context,
SharedOperationBuffers &shared_buffers,
Span<NodeOperation *> operations);
- ~FullFrameExecutionModel();
void execute(ExecutionSystem &exec_system) override;
- void execute_work(const rcti &work_rect,
- std::function<void(const rcti &split_rect)> work_func) override;
-
private:
void determine_areas_to_render_and_reads();
- void render_operations(ExecutionSystem &exec_system);
- void render_output_dependencies(NodeOperation *output_op, ExecutionSystem &exec_system);
+ void render_operations();
+ void render_output_dependencies(NodeOperation *output_op);
Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op);
MemoryBuffer *create_operation_buffer(NodeOperation *op);
- void render_operation(NodeOperation *op, ExecutionSystem &exec_system);
+ void render_operation(NodeOperation *op);
void operation_finished(NodeOperation *operation);
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index 44d3f059374..c7bddddd0e6 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -129,6 +129,18 @@ void MemoryBuffer::clear()
memset(m_buffer, 0, buffer_len() * m_num_channels * sizeof(float));
}
+/**
+ * Converts a single elem buffer to a full size buffer (allocates memory for all
+ * elements in resolution).
+ */
+MemoryBuffer *MemoryBuffer::inflate() const
+{
+ BLI_assert(is_a_single_elem());
+ MemoryBuffer *inflated = new MemoryBuffer(this->m_datatype, this->m_rect, false);
+ inflated->copy_from(this, this->m_rect);
+ return inflated;
+}
+
float MemoryBuffer::get_max_value() const
{
float result = this->m_buffer[0];
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index fdfd1c1c37b..89068a7b734 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -247,6 +247,8 @@ class MemoryBuffer {
return this->m_buffer;
}
+ MemoryBuffer *inflate() const;
+
inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
{
const int w = getWidth();
diff --git a/source/blender/compositor/intern/COM_MultiThreadedOperation.cc b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
index e6e98d69b36..7ccf6f76d9f 100644
--- a/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
+++ b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
@@ -12,12 +12,11 @@ MultiThreadedOperation::MultiThreadedOperation()
void MultiThreadedOperation::update_memory_buffer(MemoryBuffer *output,
const rcti &area,
- Span<MemoryBuffer *> inputs,
- ExecutionSystem &exec_system)
+ Span<MemoryBuffer *> inputs)
{
for (current_pass_ = 0; current_pass_ < num_passes_; current_pass_++) {
update_memory_buffer_started(output, area, inputs);
- exec_system.execute_work(area, [=](const rcti &split_rect) {
+ exec_system_->execute_work(area, [=](const rcti &split_rect) {
update_memory_buffer_partial(output, split_rect, inputs);
});
update_memory_buffer_finished(output, area, inputs);
diff --git a/source/blender/compositor/intern/COM_MultiThreadedOperation.h b/source/blender/compositor/intern/COM_MultiThreadedOperation.h
index ad09c4df089..a7e574ca745 100644
--- a/source/blender/compositor/intern/COM_MultiThreadedOperation.h
+++ b/source/blender/compositor/intern/COM_MultiThreadedOperation.h
@@ -64,8 +64,7 @@ class MultiThreadedOperation : public NodeOperation {
private:
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
- Span<MemoryBuffer *> inputs,
- ExecutionSystem &exec_system) override;
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_MultiThreadedRowOperation.cc b/source/blender/compositor/intern/COM_MultiThreadedRowOperation.cc
new file mode 100644
index 00000000000..6bf318bb96b
--- /dev/null
+++ b/source/blender/compositor/intern/COM_MultiThreadedRowOperation.cc
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_MultiThreadedRowOperation.h"
+
+namespace blender::compositor {
+
+MultiThreadedRowOperation::PixelCursor::PixelCursor(const int num_inputs)
+ : out(nullptr), out_stride(0), row_end(nullptr), ins(num_inputs), in_strides(num_inputs)
+{
+}
+
+void MultiThreadedRowOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ BLI_assert(output != nullptr);
+ const int width = BLI_rcti_size_x(&area);
+ PixelCursor p(inputs.size());
+ p.out_stride = output->elem_stride;
+ for (int i = 0; i < p.in_strides.size(); i++) {
+ p.in_strides[i] = inputs[i]->elem_stride;
+ }
+
+ for (int y = area.ymin; y < area.ymax; y++) {
+ p.out = output->get_elem(area.xmin, y);
+ for (int i = 0; i < p.ins.size(); i++) {
+ p.ins[i] = inputs[i]->get_elem(area.xmin, y);
+ }
+ p.row_end = p.out + width * p.out_stride;
+ update_memory_buffer_row(p);
+ }
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_MultiThreadedRowOperation.h b/source/blender/compositor/intern/COM_MultiThreadedRowOperation.h
new file mode 100644
index 00000000000..3daa9eec474
--- /dev/null
+++ b/source/blender/compositor/intern/COM_MultiThreadedRowOperation.h
@@ -0,0 +1,60 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_MultiThreadedOperation.h"
+
+namespace blender::compositor {
+
+/**
+ * Executes buffer updates per row. To be inherited only by operations with correlated coordinates
+ * between inputs and output.
+ */
+class MultiThreadedRowOperation : public MultiThreadedOperation {
+ protected:
+ struct PixelCursor {
+ float *out;
+ int out_stride;
+ const float *row_end;
+ Array<const float *> ins;
+ Array<int> in_strides;
+
+ public:
+ PixelCursor(int num_inputs);
+
+ void next()
+ {
+ BLI_assert(out < row_end);
+ out += out_stride;
+ for (int i = 0; i < ins.size(); i++) {
+ ins[i] += in_strides[i];
+ }
+ }
+ };
+
+ protected:
+ virtual void update_memory_buffer_row(PixelCursor &p) = 0;
+
+ private:
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) final;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc
index b943ab6af7f..6484c75f364 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cc
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -226,18 +226,16 @@ void NodeOperation::get_area_of_interest(NodeOperation *input_op,
* \param output_buf: Buffer to write result to.
* \param areas: Areas within this operation bounds to render.
* \param inputs_bufs: Inputs operations buffers.
- * \param exec_system: Execution system.
*/
void NodeOperation::render(MemoryBuffer *output_buf,
Span<rcti> areas,
- Span<MemoryBuffer *> inputs_bufs,
- ExecutionSystem &exec_system)
+ Span<MemoryBuffer *> inputs_bufs)
{
if (get_flags().is_fullframe_operation) {
- render_full_frame(output_buf, areas, inputs_bufs, exec_system);
+ render_full_frame(output_buf, areas, inputs_bufs);
}
else {
- render_full_frame_fallback(output_buf, areas, inputs_bufs, exec_system);
+ render_full_frame_fallback(output_buf, areas, inputs_bufs);
}
}
@@ -246,12 +244,11 @@ void NodeOperation::render(MemoryBuffer *output_buf,
*/
void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
- Span<MemoryBuffer *> inputs_bufs,
- ExecutionSystem &exec_system)
+ Span<MemoryBuffer *> inputs_bufs)
{
initExecution();
for (const rcti &area : areas) {
- update_memory_buffer(output_buf, area, inputs_bufs, exec_system);
+ update_memory_buffer(output_buf, area, inputs_bufs);
}
deinitExecution();
}
@@ -261,8 +258,7 @@ void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
*/
void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
- Span<MemoryBuffer *> inputs_bufs,
- ExecutionSystem &exec_system)
+ Span<MemoryBuffer *> inputs_bufs)
{
Vector<NodeOperationOutput *> orig_input_links = replace_inputs_with_buffers(inputs_bufs);
@@ -274,7 +270,7 @@ void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
}
else {
for (const rcti &rect : areas) {
- exec_system.execute_work(rect, [=](const rcti &split_rect) {
+ exec_system_->execute_work(rect, [=](const rcti &split_rect) {
rcti tile_rect = split_rect;
if (is_output_operation) {
executeRegion(&tile_rect, 0);
@@ -328,6 +324,7 @@ Vector<NodeOperationOutput *> NodeOperation::replace_inputs_with_buffers(
BufferOperation *buffer_op = new BufferOperation(inputs_bufs[i], input_socket->getDataType());
orig_links[i] = input_socket->getLink();
input_socket->setLink(buffer_op->getOutputSocket());
+ buffer_op->initExecution();
}
return orig_links;
}
@@ -340,6 +337,7 @@ void NodeOperation::remove_buffers_and_restore_original_inputs(
NodeOperation *buffer_op = get_input_operation(i);
BLI_assert(buffer_op != nullptr);
BLI_assert(typeid(*buffer_op) == typeid(BufferOperation));
+ buffer_op->deinitExecution();
NodeOperationInput *input_socket = getInputSocket(i);
input_socket->setLink(original_inputs_links[i]);
delete buffer_op;
@@ -443,6 +441,12 @@ std::ostream &operator<<(std::ostream &os, const NodeOperationFlags &node_operat
if (node_operation_flags.is_fullframe_operation) {
os << "full_frame,";
}
+ if (node_operation_flags.is_constant_operation) {
+ os << "contant_operation,";
+ }
+ if (node_operation_flags.can_be_constant) {
+ os << "can_be_constant,";
+ }
return os;
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index 5ae0aae67d5..fb9ec1e7a83 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -221,6 +221,7 @@ struct NodeOperationFlags {
/**
* Is this a set operation (value, color, vector).
+ * TODO: To be replaced by is_constant_operation flag once tiled implementation is removed.
*/
bool is_set_operation : 1;
bool is_write_buffer_operation : 1;
@@ -242,6 +243,17 @@ struct NodeOperationFlags {
*/
bool is_fullframe_operation : 1;
+ /**
+ * Whether operation is a primitive constant operation (Color/Vector/Value).
+ */
+ bool is_constant_operation : 1;
+
+ /**
+ * Whether operation have constant elements/pixels values when all its inputs are constant
+ * operations.
+ */
+ bool can_be_constant : 1;
+
NodeOperationFlags()
{
complex = false;
@@ -258,6 +270,8 @@ struct NodeOperationFlags {
is_preview_operation = false;
use_datatype_conversion = true;
is_fullframe_operation = false;
+ is_constant_operation = false;
+ can_be_constant = false;
}
};
@@ -316,6 +330,8 @@ class NodeOperation {
*/
NodeOperationFlags flags;
+ ExecutionSystem *exec_system_;
+
public:
virtual ~NodeOperation()
{
@@ -402,6 +418,12 @@ class NodeOperation {
{
this->m_btree = tree;
}
+
+ void set_execution_system(ExecutionSystem *system)
+ {
+ exec_system_ = system;
+ }
+
virtual void initExecution();
/**
@@ -569,18 +591,14 @@ class NodeOperation {
/** \name Full Frame Methods
* \{ */
- void render(MemoryBuffer *output_buf,
- Span<rcti> areas,
- Span<MemoryBuffer *> inputs_bufs,
- ExecutionSystem &exec_system);
+ void render(MemoryBuffer *output_buf, Span<rcti> areas, Span<MemoryBuffer *> inputs_bufs);
/**
* Executes operation updating output memory buffer. Single-threaded calls.
*/
virtual void update_memory_buffer(MemoryBuffer *UNUSED(output),
const rcti &UNUSED(area),
- Span<MemoryBuffer *> UNUSED(inputs),
- ExecutionSystem &UNUSED(exec_system))
+ Span<MemoryBuffer *> UNUSED(inputs))
{
}
@@ -678,13 +696,11 @@ class NodeOperation {
void render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
- Span<MemoryBuffer *> inputs_bufs,
- ExecutionSystem &exec_system);
+ Span<MemoryBuffer *> inputs_bufs);
void render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
- Span<MemoryBuffer *> inputs,
- ExecutionSystem &exec_system);
+ Span<MemoryBuffer *> inputs);
void render_tile(MemoryBuffer *output_buf, rcti *tile_rect);
Vector<NodeOperationOutput *> replace_inputs_with_buffers(Span<MemoryBuffer *> inputs_bufs);
void remove_buffers_and_restore_original_inputs(
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 3036e3f55dd..10a91bbcd3e 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -36,12 +36,15 @@
#include "COM_ViewerOperation.h"
#include "COM_WriteBufferOperation.h"
+#include "COM_ConstantFolder.h"
#include "COM_NodeOperationBuilder.h" /* own include */
namespace blender::compositor {
-NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree)
- : m_context(context), m_current_node(nullptr), m_active_viewer(nullptr)
+NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context,
+ bNodeTree *b_nodetree,
+ ExecutionSystem *system)
+ : m_context(context), exec_system_(system), m_current_node(nullptr), m_active_viewer(nullptr)
{
m_graph.from_bNodeTree(*context, b_nodetree);
}
@@ -97,6 +100,15 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
add_datatype_conversions();
+ if (m_context->get_execution_model() == eExecutionModel::FullFrame) {
+ /* Copy operations to system. Needed for graphviz. */
+ system->set_operations(m_operations, {});
+
+ DebugInfo::graphviz(system, "compositor_prior_folding");
+ ConstantFolder folder(*this);
+ folder.fold_operations();
+ }
+
determineResolutions();
if (m_context->get_execution_model() == eExecutionModel::Tiled) {
@@ -130,6 +142,29 @@ void NodeOperationBuilder::addOperation(NodeOperation *operation)
operation->set_name(m_current_node->getbNode()->name);
}
operation->set_execution_model(m_context->get_execution_model());
+ operation->set_execution_system(exec_system_);
+}
+
+void NodeOperationBuilder::replace_operation_with_constant(NodeOperation *operation,
+ ConstantOperation *constant_operation)
+{
+ BLI_assert(constant_operation->getNumberOfInputSockets() == 0);
+ int i = 0;
+ while (i < m_links.size()) {
+ Link &link = m_links[i];
+ if (&link.to()->getOperation() == operation) {
+ link.to()->setLink(nullptr);
+ m_links.remove(i);
+ continue;
+ }
+
+ if (&link.from()->getOperation() == operation) {
+ link.to()->setLink(constant_operation->getOutputSocket());
+ m_links[i] = Link(constant_operation->getOutputSocket(), link.to());
+ }
+ i++;
+ }
+ addOperation(constant_operation);
}
void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket,
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
index b2fb822af25..1f76765c846 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
@@ -41,6 +41,7 @@ class NodeOperationOutput;
class PreviewOperation;
class WriteBufferOperation;
class ViewerOperation;
+class ConstantOperation;
class NodeOperationBuilder {
public:
@@ -67,6 +68,7 @@ class NodeOperationBuilder {
private:
const CompositorContext *m_context;
NodeGraph m_graph;
+ ExecutionSystem *exec_system_;
Vector<NodeOperation *> m_operations;
Vector<Link> m_links;
@@ -86,7 +88,9 @@ class NodeOperationBuilder {
ViewerOperation *m_active_viewer;
public:
- NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree);
+ NodeOperationBuilder(const CompositorContext *context,
+ bNodeTree *b_nodetree,
+ ExecutionSystem *system);
const CompositorContext &context() const
{
@@ -96,6 +100,8 @@ class NodeOperationBuilder {
void convertToOperations(ExecutionSystem *system);
void addOperation(NodeOperation *operation);
+ void replace_operation_with_constant(NodeOperation *operation,
+ ConstantOperation *constant_operation);
/** Map input socket of the current node to an operation socket */
void mapInputSocket(NodeInput *node_socket, NodeOperationInput *operation_socket);
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cc b/source/blender/compositor/intern/COM_WorkScheduler.cc
index 157ded943d6..8e49bf34b51 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cc
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cc
@@ -126,7 +126,7 @@ static void *thread_execute_gpu(void *data)
return nullptr;
}
-static void opencl_start(CompositorContext &context)
+static void opencl_start(const CompositorContext &context)
{
if (context.getHasActiveOpenCLDevices()) {
g_work_scheduler.opencl.queue = BLI_thread_queue_init();
@@ -458,7 +458,7 @@ void WorkScheduler::schedule(WorkPackage *package)
}
}
-void WorkScheduler::start(CompositorContext &context)
+void WorkScheduler::start(const CompositorContext &context)
{
if (COM_is_opencl_enabled()) {
opencl_start(context);
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h
index be88859be7c..297943aa63b 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.h
+++ b/source/blender/compositor/intern/COM_WorkScheduler.h
@@ -65,7 +65,7 @@ struct WorkScheduler {
* for every device a thread is created.
* \see initialize Initialization and query of the number of devices
*/
- static void start(CompositorContext &context);
+ static void start(const CompositorContext &context);
/**
* \brief stop the execution
diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
index d1d3752e402..aee8c0d52e8 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
@@ -41,6 +41,7 @@ ColorBalanceASCCDLOperation::ColorBalanceASCCDLOperation()
this->m_inputValueOperation = nullptr;
this->m_inputColorOperation = nullptr;
this->setResolutionInputSocketIndex(1);
+ flags.can_be_constant = true;
}
void ColorBalanceASCCDLOperation::initExecution()
@@ -76,6 +77,23 @@ void ColorBalanceASCCDLOperation::executePixelSampled(float output[4],
output[3] = inputColor[3];
}
+void ColorBalanceASCCDLOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *in_factor = p.ins[0];
+ const float *in_color = p.ins[1];
+ const float fac = MIN2(1.0f, in_factor[0]);
+ const float fac_m = 1.0f - fac;
+ p.out[0] = fac_m * in_color[0] +
+ fac * colorbalance_cdl(in_color[0], m_offset[0], m_power[0], m_slope[0]);
+ p.out[1] = fac_m * in_color[1] +
+ fac * colorbalance_cdl(in_color[1], m_offset[1], m_power[1], m_slope[1]);
+ p.out[2] = fac_m * in_color[2] +
+ fac * colorbalance_cdl(in_color[2], m_offset[2], m_power[2], m_slope[2]);
+ p.out[3] = in_color[3];
+ }
+}
+
void ColorBalanceASCCDLOperation::deinitExecution()
{
this->m_inputValueOperation = nullptr;
diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h
index 5851600190f..d161ea66af2 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h
+++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedRowOperation.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 ColorBalanceASCCDLOperation : public NodeOperation {
+class ColorBalanceASCCDLOperation : public MultiThreadedRowOperation {
protected:
/**
* Prefetched reference to the inputProgram
@@ -71,6 +71,8 @@ class ColorBalanceASCCDLOperation : public NodeOperation {
{
copy_v3_v3(this->m_slope, slope);
}
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
index cac16a3f7b0..674cb79a238 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
@@ -46,6 +46,7 @@ ColorBalanceLGGOperation::ColorBalanceLGGOperation()
this->m_inputValueOperation = nullptr;
this->m_inputColorOperation = nullptr;
this->setResolutionInputSocketIndex(1);
+ flags.can_be_constant = true;
}
void ColorBalanceLGGOperation::initExecution()
@@ -81,6 +82,23 @@ void ColorBalanceLGGOperation::executePixelSampled(float output[4],
output[3] = inputColor[3];
}
+void ColorBalanceLGGOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *in_factor = p.ins[0];
+ const float *in_color = p.ins[1];
+ const float fac = MIN2(1.0f, in_factor[0]);
+ const float fac_m = 1.0f - fac;
+ p.out[0] = fac_m * in_color[0] +
+ fac * colorbalance_lgg(in_color[0], m_lift[0], m_gamma_inv[0], m_gain[0]);
+ p.out[1] = fac_m * in_color[1] +
+ fac * colorbalance_lgg(in_color[1], m_lift[1], m_gamma_inv[1], m_gain[1]);
+ p.out[2] = fac_m * in_color[2] +
+ fac * colorbalance_lgg(in_color[2], m_lift[2], m_gamma_inv[2], m_gain[2]);
+ p.out[3] = in_color[3];
+ }
+}
+
void ColorBalanceLGGOperation::deinitExecution()
{
this->m_inputValueOperation = nullptr;
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h
index 23f70247b66..4bc929ed76c 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedRowOperation.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 ColorBalanceLGGOperation : public NodeOperation {
+class ColorBalanceLGGOperation : public MultiThreadedRowOperation {
protected:
/**
* Prefetched reference to the inputProgram
@@ -71,6 +71,8 @@ class ColorBalanceLGGOperation : public NodeOperation {
{
copy_v3_v3(this->m_gamma_inv, gamma_inv);
}
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
index 168e9b57eb2..b50145b106d 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
@@ -33,6 +33,7 @@ ColorCorrectionOperation::ColorCorrectionOperation()
this->m_redChannelEnabled = true;
this->m_greenChannelEnabled = true;
this->m_blueChannelEnabled = true;
+ flags.can_be_constant = true;
}
void ColorCorrectionOperation::initExecution()
{
@@ -157,6 +158,86 @@ void ColorCorrectionOperation::executePixelSampled(float output[4],
output[3] = inputImageColor[3];
}
+void ColorCorrectionOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *in_color = p.ins[0];
+ const float *in_mask = p.ins[1];
+
+ const float level = (in_color[0] + in_color[1] + in_color[2]) / 3.0f;
+ float level_shadows = 0.0f;
+ float level_midtones = 0.0f;
+ float level_highlights = 0.0f;
+ constexpr float MARGIN = 0.10f;
+ constexpr float MARGIN_DIV = 0.5f / MARGIN;
+ if (level < this->m_data->startmidtones - MARGIN) {
+ level_shadows = 1.0f;
+ }
+ else if (level < this->m_data->startmidtones + MARGIN) {
+ level_midtones = ((level - this->m_data->startmidtones) * MARGIN_DIV) + 0.5f;
+ level_shadows = 1.0f - level_midtones;
+ }
+ else if (level < this->m_data->endmidtones - MARGIN) {
+ level_midtones = 1.0f;
+ }
+ else if (level < this->m_data->endmidtones + MARGIN) {
+ level_highlights = ((level - this->m_data->endmidtones) * MARGIN_DIV) + 0.5f;
+ level_midtones = 1.0f - level_highlights;
+ }
+ else {
+ level_highlights = 1.0f;
+ }
+ float contrast = this->m_data->master.contrast;
+ float saturation = this->m_data->master.saturation;
+ float gamma = this->m_data->master.gamma;
+ float gain = this->m_data->master.gain;
+ float lift = this->m_data->master.lift;
+ contrast *= level_shadows * this->m_data->shadows.contrast +
+ level_midtones * this->m_data->midtones.contrast +
+ level_highlights * this->m_data->highlights.contrast;
+ saturation *= level_shadows * this->m_data->shadows.saturation +
+ level_midtones * this->m_data->midtones.saturation +
+ level_highlights * this->m_data->highlights.saturation;
+ gamma *= level_shadows * this->m_data->shadows.gamma +
+ level_midtones * this->m_data->midtones.gamma +
+ level_highlights * this->m_data->highlights.gamma;
+ gain *= level_shadows * this->m_data->shadows.gain +
+ level_midtones * this->m_data->midtones.gain +
+ level_highlights * this->m_data->highlights.gain;
+ lift += level_shadows * this->m_data->shadows.lift +
+ level_midtones * this->m_data->midtones.lift +
+ level_highlights * this->m_data->highlights.lift;
+
+ const float inv_gamma = 1.0f / gamma;
+ const float luma = IMB_colormanagement_get_luminance(in_color);
+
+ float r = luma + saturation * (in_color[0] - luma);
+ float g = luma + saturation * (in_color[1] - luma);
+ float b = luma + saturation * (in_color[2] - luma);
+
+ r = 0.5f + (r - 0.5f) * contrast;
+ g = 0.5f + (g - 0.5f) * contrast;
+ b = 0.5f + (b - 0.5f) * contrast;
+
+ /* Check for negative values to avoid nan. */
+ r = color_correct_powf_safe(r * gain + lift, inv_gamma, r);
+ g = color_correct_powf_safe(g * gain + lift, inv_gamma, g);
+ b = color_correct_powf_safe(b * gain + lift, inv_gamma, b);
+
+ /* Mix with mask. */
+ const float value = MIN2(1.0f, in_mask[0]);
+ const float m_value = 1.0f - value;
+ r = m_value * in_color[0] + value * r;
+ g = m_value * in_color[1] + value * g;
+ b = m_value * in_color[2] + value * b;
+
+ p.out[0] = m_redChannelEnabled ? r : in_color[0];
+ p.out[1] = m_greenChannelEnabled ? g : in_color[1];
+ p.out[2] = m_blueChannelEnabled ? b : in_color[2];
+ p.out[3] = in_color[3];
+ }
+}
+
void ColorCorrectionOperation::deinitExecution()
{
this->m_inputImage = nullptr;
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.h b/source/blender/compositor/operations/COM_ColorCorrectionOperation.h
index c5826ed0152..32b5e02e77a 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.h
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedRowOperation.h"
namespace blender::compositor {
-class ColorCorrectionOperation : public NodeOperation {
+class ColorCorrectionOperation : public MultiThreadedRowOperation {
private:
/**
* Cached reference to the inputProgram
@@ -69,6 +69,8 @@ class ColorCorrectionOperation : public NodeOperation {
{
this->m_blueChannelEnabled = enabled;
}
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cc b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
index 1512ff87658..228550a31c5 100644
--- a/source/blender/compositor/operations/COM_ColorExposureOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
@@ -26,6 +26,7 @@ ExposureOperation::ExposureOperation()
this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Color);
this->m_inputProgram = nullptr;
+ flags.can_be_constant = true;
}
void ExposureOperation::initExecution()
@@ -52,6 +53,19 @@ void ExposureOperation::executePixelSampled(float output[4],
output[3] = inputValue[3];
}
+void ExposureOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *in_value = p.ins[0];
+ const float *in_exposure = p.ins[1];
+ const float exposure = pow(2, in_exposure[0]);
+ p.out[0] = in_value[0] * exposure;
+ p.out[1] = in_value[1] * exposure;
+ p.out[2] = in_value[2] * exposure;
+ p.out[3] = in_value[3];
+ }
+}
+
void ExposureOperation::deinitExecution()
{
this->m_inputProgram = nullptr;
diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.h b/source/blender/compositor/operations/COM_ColorExposureOperation.h
index 0cfaa059e41..1eb790e8d52 100644
--- a/source/blender/compositor/operations/COM_ColorExposureOperation.h
+++ b/source/blender/compositor/operations/COM_ColorExposureOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedRowOperation.h"
namespace blender::compositor {
-class ExposureOperation : public NodeOperation {
+class ExposureOperation : public MultiThreadedRowOperation {
private:
/**
* Cached reference to the inputProgram
@@ -47,6 +47,8 @@ class ExposureOperation : public NodeOperation {
* Deinitialize the execution
*/
void deinitExecution() override;
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConstantOperation.cc b/source/blender/compositor/operations/COM_ConstantOperation.cc
new file mode 100644
index 00000000000..f905edbde76
--- /dev/null
+++ b/source/blender/compositor/operations/COM_ConstantOperation.cc
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_ConstantOperation.h"
+
+namespace blender::compositor {
+
+ConstantOperation::ConstantOperation()
+{
+ flags.is_constant_operation = true;
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConstantOperation.h b/source/blender/compositor/operations/COM_ConstantOperation.h
new file mode 100644
index 00000000000..2709efeebd8
--- /dev/null
+++ b/source/blender/compositor/operations/COM_ConstantOperation.h
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_NodeOperation.h"
+
+namespace blender::compositor {
+
+/**
+ * Base class for primitive constant operations (Color/Vector/Value). The rest of operations that
+ * can be constant are evaluated into primitives during constant folding.
+ */
+class ConstantOperation : public NodeOperation {
+ public:
+ ConstantOperation();
+
+ virtual const float *get_constant_elem() = 0;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GammaOperation.cc b/source/blender/compositor/operations/COM_GammaOperation.cc
index 343e335070a..396d3942b06 100644
--- a/source/blender/compositor/operations/COM_GammaOperation.cc
+++ b/source/blender/compositor/operations/COM_GammaOperation.cc
@@ -28,6 +28,7 @@ GammaOperation::GammaOperation()
this->addOutputSocket(DataType::Color);
this->m_inputProgram = nullptr;
this->m_inputGammaProgram = nullptr;
+ flags.can_be_constant = true;
}
void GammaOperation::initExecution()
{
@@ -51,6 +52,20 @@ void GammaOperation::executePixelSampled(float output[4], float x, float y, Pixe
output[3] = inputValue[3];
}
+void GammaOperation::update_memory_buffer_row(PixelCursor &p)
+{
+ for (; p.out < p.row_end; p.next()) {
+ const float *in_value = p.ins[0];
+ const float *in_gamma = p.ins[1];
+ const float gamma = in_gamma[0];
+ /* Check for negative to avoid nan's. */
+ p.out[0] = in_value[0] > 0.0f ? powf(in_value[0], gamma) : in_value[0];
+ p.out[1] = in_value[1] > 0.0f ? powf(in_value[1], gamma) : in_value[1];
+ p.out[2] = in_value[2] > 0.0f ? powf(in_value[2], gamma) : in_value[2];
+ p.out[3] = in_value[3];
+ }
+}
+
void GammaOperation::deinitExecution()
{
this->m_inputProgram = nullptr;
diff --git a/source/blender/compositor/operations/COM_GammaOperation.h b/source/blender/compositor/operations/COM_GammaOperation.h
index 034046106d6..713d3d8484f 100644
--- a/source/blender/compositor/operations/COM_GammaOperation.h
+++ b/source/blender/compositor/operations/COM_GammaOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedRowOperation.h"
namespace blender::compositor {
-class GammaOperation : public NodeOperation {
+class GammaOperation : public MultiThreadedRowOperation {
private:
/**
* Cached reference to the inputProgram
@@ -47,6 +47,8 @@ class GammaOperation : public NodeOperation {
* Deinitialize the execution
*/
void deinitExecution() override;
+
+ void update_memory_buffer_row(PixelCursor &p) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cc b/source/blender/compositor/operations/COM_IDMaskOperation.cc
index 38f8b7e075f..bb11ac8b1be 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc
@@ -25,6 +25,7 @@ IDMaskOperation::IDMaskOperation()
this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Value);
this->flags.complex = true;
+ flags.can_be_constant = true;
}
void *IDMaskOperation::initializeTileData(rcti *rect)
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cc b/source/blender/compositor/operations/COM_NormalizeOperation.cc
index faacb429f71..f93afcaab95 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cc
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc
@@ -36,7 +36,7 @@ void NormalizeOperation::initExecution()
void NormalizeOperation::executePixel(float output[4], int x, int y, void *data)
{
- /* using generic two floats struct to store x: min y: mult */
+ /* using generic two floats struct to store `x: min`, `y: multiply` */
NodeTwoFloats *minmult = (NodeTwoFloats *)data;
this->m_imageReader->read(output, x, y, nullptr);
@@ -89,7 +89,7 @@ void *NormalizeOperation::initializeTileData(rcti *rect)
lockMutex();
if (this->m_cachedInstance == nullptr) {
MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect);
- /* using generic two floats struct to store x: min y: mult */
+ /* using generic two floats struct to store `x: min`, `y: multiply`. */
NodeTwoFloats *minmult = new NodeTwoFloats();
float *buffer = tile->getBuffer();
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.h b/source/blender/compositor/operations/COM_NormalizeOperation.h
index 93d4a0fc67d..c89ba372189 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.h
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.h
@@ -36,7 +36,7 @@ class NormalizeOperation : public NodeOperation {
/**
* \brief temporarily cache of the execution storage
- * it stores x->min and y->mult
+ * it stores `x->min` and `y->multiply`.
*/
NodeTwoFloats *m_cachedInstance;
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index 9dde73269fc..c3647a39909 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -36,12 +36,12 @@ namespace blender::compositor {
*
* http://www.iryoku.com/smaa/
*
- * This file is based on smaa-cpp:
+ * This file is based on SMAA-CPP:
*
* https://github.com/iRi-E/smaa-cpp
*
* Currently only SMAA 1x mode is provided, so the operation will be done
- * with no spatial multisampling nor temporal supersampling.
+ * with no spatial multi-sampling nor temporal super-sampling.
*
* NOTE: This program assumes the screen coordinates are DirectX style, so
* the vertical direction is upside-down. "top" and "bottom" actually mean
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cc b/source/blender/compositor/operations/COM_SetColorOperation.cc
index 79dee33e266..bfe735aab15 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cc
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cc
@@ -44,8 +44,7 @@ void SetColorOperation::determineResolution(unsigned int resolution[2],
void SetColorOperation::update_memory_buffer(MemoryBuffer *output,
const rcti &area,
- Span<MemoryBuffer *> UNUSED(inputs),
- ExecutionSystem &UNUSED(exec_system))
+ Span<MemoryBuffer *> UNUSED(inputs))
{
BLI_assert(output->is_a_single_elem());
float *out_elem = output->get_elem(area.xmin, area.ymin);
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.h b/source/blender/compositor/operations/COM_SetColorOperation.h
index 2e22ef60ba4..f4c0948ee1b 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.h
+++ b/source/blender/compositor/operations/COM_SetColorOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_ConstantOperation.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 SetColorOperation : public NodeOperation {
+class SetColorOperation : public ConstantOperation {
private:
float m_color[4];
@@ -36,6 +36,11 @@ class SetColorOperation : public NodeOperation {
*/
SetColorOperation();
+ const float *get_constant_elem() override
+ {
+ return m_color;
+ }
+
float getChannel1()
{
return this->m_color[0];
@@ -83,8 +88,7 @@ class SetColorOperation : public NodeOperation {
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
- Span<MemoryBuffer *> inputs,
- ExecutionSystem &exec_system) override;
+ 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 359647c8fe3..c12fb106afd 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cc
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cc
@@ -44,8 +44,7 @@ void SetValueOperation::determineResolution(unsigned int resolution[2],
void SetValueOperation::update_memory_buffer(MemoryBuffer *output,
const rcti &area,
- Span<MemoryBuffer *> UNUSED(inputs),
- ExecutionSystem &UNUSED(exec_system))
+ Span<MemoryBuffer *> UNUSED(inputs))
{
BLI_assert(output->is_a_single_elem());
float *out_elem = output->get_elem(area.xmin, area.ymin);
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.h b/source/blender/compositor/operations/COM_SetValueOperation.h
index acde5aa03b7..f18d44d9554 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.h
+++ b/source/blender/compositor/operations/COM_SetValueOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_ConstantOperation.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 SetValueOperation : public NodeOperation {
+class SetValueOperation : public ConstantOperation {
private:
float m_value;
@@ -36,6 +36,11 @@ class SetValueOperation : public NodeOperation {
*/
SetValueOperation();
+ const float *get_constant_elem() override
+ {
+ return &m_value;
+ }
+
float getValue()
{
return this->m_value;
@@ -53,8 +58,7 @@ class SetValueOperation : public NodeOperation {
unsigned int preferredResolution[2]) override;
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
- Span<MemoryBuffer *> inputs,
- ExecutionSystem &exec_system) override;
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cc b/source/blender/compositor/operations/COM_SetVectorOperation.cc
index 7152d5e61d4..7b8cf44048c 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.cc
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc
@@ -32,9 +32,9 @@ void SetVectorOperation::executePixelSampled(float output[4],
float /*y*/,
PixelSampler /*sampler*/)
{
- output[0] = this->m_x;
- output[1] = this->m_y;
- output[2] = this->m_z;
+ output[0] = vector_.x;
+ output[1] = vector_.y;
+ output[2] = vector_.z;
}
void SetVectorOperation::determineResolution(unsigned int resolution[2],
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.h b/source/blender/compositor/operations/COM_SetVectorOperation.h
index b444339fcb2..41fd06659d6 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.h
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_ConstantOperation.h"
namespace blender::compositor {
@@ -26,12 +26,14 @@ namespace blender::compositor {
* this program converts an input color to an output value.
* it assumes we are in sRGB color space.
*/
-class SetVectorOperation : public NodeOperation {
+class SetVectorOperation : public ConstantOperation {
private:
- float m_x;
- float m_y;
- float m_z;
- float m_w;
+ struct {
+ float x;
+ float y;
+ float z;
+ float w;
+ } vector_;
public:
/**
@@ -39,37 +41,42 @@ class SetVectorOperation : public NodeOperation {
*/
SetVectorOperation();
+ const float *get_constant_elem() override
+ {
+ return reinterpret_cast<float *>(&vector_);
+ }
+
float getX()
{
- return this->m_x;
+ return vector_.x;
}
void setX(float value)
{
- this->m_x = value;
+ vector_.x = value;
}
float getY()
{
- return this->m_y;
+ return vector_.y;
}
void setY(float value)
{
- this->m_y = value;
+ vector_.y = value;
}
float getZ()
{
- return this->m_z;
+ return vector_.z;
}
void setZ(float value)
{
- this->m_z = value;
+ vector_.z = value;
}
float getW()
{
- return this->m_w;
+ return vector_.w;
}
void setW(float value)
{
- this->m_w = value;
+ vector_.w = value;
}
/**
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
index 5adcc4fdd4c..b5b5d426338 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
@@ -432,7 +432,7 @@ void antialias_tagbuf(int xsize, int ysize, char *rectmove)
}
}
- /* 2: evaluate horizontal scanlines and calculate alphas */
+ /* 2: evaluate horizontal scan-lines and calculate alphas. */
row1 = rectmove;
for (y = 0; y < ysize; y++) {
row1++;
@@ -463,7 +463,7 @@ void antialias_tagbuf(int xsize, int ysize, char *rectmove)
}
}
- /* 3: evaluate vertical scanlines and calculate alphas */
+ /* 3: evaluate vertical scan-lines and calculate alphas */
/* use for reading a copy of the original tagged buffer */
for (x = 0; x < xsize; x++) {
row1 = rectmove + x + xsize;