[Bf-blender-cvs] [cc08debc0cc] temp-geometry-nodes-evaluator-refactor: make nodes with side effects work
Jacques Lucke
noreply at git.blender.org
Tue Sep 6 20:09:56 CEST 2022
Commit: cc08debc0cc76f63f9517a4a06581c475ae2eae4
Author: Jacques Lucke
Date: Tue Sep 6 19:24:13 2022 +0200
Branches: temp-geometry-nodes-evaluator-refactor
https://developer.blender.org/rBcc08debc0cc76f63f9517a4a06581c475ae2eae4
make nodes with side effects work
===================================================================
M source/blender/functions/FN_lazy_function.hh
M source/blender/functions/FN_lazy_function_execute.hh
M source/blender/functions/FN_lazy_function_graph_executor.hh
M source/blender/functions/intern/lazy_function.cc
M source/blender/functions/intern/lazy_function_graph_executor.cc
M source/blender/functions/tests/FN_lazy_function_test.cc
===================================================================
diff --git a/source/blender/functions/FN_lazy_function.hh b/source/blender/functions/FN_lazy_function.hh
index f6528907c1b..3a332df34ce 100644
--- a/source/blender/functions/FN_lazy_function.hh
+++ b/source/blender/functions/FN_lazy_function.hh
@@ -79,6 +79,7 @@ class Params {
template<typename T> T extract_input(int index);
template<typename T> const T &get_input(int index);
+ template<typename T> T *try_get_input_data_ptr_or_request(int index);
template<typename T> void set_output(int index, T &&value);
void set_default_remaining_outputs();
@@ -134,7 +135,7 @@ class LazyFunction {
void execute(Params ¶ms, const Context &context) const;
- bool valid_params_for_execution(const Params ¶ms) const;
+ bool always_used_inputs_available(const Params ¶ms) const;
private:
virtual void execute_impl(Params ¶ms, const Context &context) const = 0;
@@ -156,7 +157,7 @@ inline Span<Output> LazyFunction::outputs() const
inline void LazyFunction::execute(Params ¶ms, const Context &context) const
{
- BLI_assert(this->valid_params_for_execution(params));
+ BLI_assert(this->always_used_inputs_available(params));
this->execute_impl(params, context);
}
@@ -170,42 +171,42 @@ inline Params::Params(const LazyFunction &fn) : fn_(fn)
{
}
-inline void *Params::try_get_input_data_ptr(int index) const
+inline void *Params::try_get_input_data_ptr(const int index) const
{
return this->try_get_input_data_ptr_impl(index);
}
-inline void *Params::try_get_input_data_ptr_or_request(int index)
+inline void *Params::try_get_input_data_ptr_or_request(const int index)
{
return this->try_get_input_data_ptr_or_request_impl(index);
}
-inline void *Params::get_output_data_ptr(int index)
+inline void *Params::get_output_data_ptr(const int index)
{
return this->get_output_data_ptr_impl(index);
}
-inline void Params::output_set(int index)
+inline void Params::output_set(const int index)
{
this->output_set_impl(index);
}
-inline bool Params::output_was_set(int index) const
+inline bool Params::output_was_set(const int index) const
{
return this->output_was_set_impl(index);
}
-inline ValueUsage Params::get_output_usage(int index) const
+inline ValueUsage Params::get_output_usage(const int index) const
{
return this->get_output_usage_impl(index);
}
-inline void Params::set_input_unused(int index)
+inline void Params::set_input_unused(const int index)
{
this->set_input_unused_impl(index);
}
-template<typename T> inline T Params::extract_input(int index)
+template<typename T> inline T Params::extract_input(const int index)
{
void *data = this->try_get_input_data_ptr(index);
BLI_assert(data != nullptr);
@@ -213,14 +214,19 @@ template<typename T> inline T Params::extract_input(int index)
return return_value;
}
-template<typename T> inline const T &Params::get_input(int index)
+template<typename T> inline const T &Params::get_input(const int index)
{
const void *data = this->try_get_input_data_ptr(index);
BLI_assert(data != nullptr);
return *static_cast<const T *>(data);
}
-template<typename T> inline void Params::set_output(int index, T &&value)
+template<typename T> inline T *Params::try_get_input_data_ptr_or_request(const int index)
+{
+ return static_cast<T *>(this->try_get_input_data_ptr_or_request(index));
+}
+
+template<typename T> inline void Params::set_output(const int index, T &&value)
{
using DecayT = std::decay_t<T>;
void *data = this->get_output_data_ptr(index);
diff --git a/source/blender/functions/FN_lazy_function_execute.hh b/source/blender/functions/FN_lazy_function_execute.hh
index c378e5fe2ac..d6a7ddcbd2a 100644
--- a/source/blender/functions/FN_lazy_function_execute.hh
+++ b/source/blender/functions/FN_lazy_function_execute.hh
@@ -75,6 +75,7 @@ inline void execute_lazy_function_eagerly_impl(
set_outputs.fill(false);
LinearAllocator<> allocator;
Context context;
+ context.user_data = user_data;
context.storage = fn.init_storage(allocator);
BasicParams params{
fn, input_pointers, output_pointers, input_usages, output_usages, set_outputs};
diff --git a/source/blender/functions/FN_lazy_function_graph_executor.hh b/source/blender/functions/FN_lazy_function_graph_executor.hh
index 86a7592e982..64f6059f7b6 100644
--- a/source/blender/functions/FN_lazy_function_graph_executor.hh
+++ b/source/blender/functions/FN_lazy_function_graph_executor.hh
@@ -15,6 +15,8 @@ namespace blender::fn::lazy_function {
class LazyFunctionGraphExecutionLogger {
public:
+ virtual ~LazyFunctionGraphExecutionLogger() = default;
+
virtual void log_socket_value(const Context &context,
const Socket &socket,
GPointer value) const;
@@ -22,7 +24,8 @@ class LazyFunctionGraphExecutionLogger {
class LazyFunctionGraphExecutionSideEffectProvider {
public:
- virtual Vector<const Node *> get_nodes_with_side_effects(const Context &context) const;
+ virtual ~LazyFunctionGraphExecutionSideEffectProvider() = default;
+ virtual Vector<const FunctionNode *> get_nodes_with_side_effects(const Context &context) const;
};
class LazyFunctionGraphExecutor : public LazyFunction {
diff --git a/source/blender/functions/intern/lazy_function.cc b/source/blender/functions/intern/lazy_function.cc
index 7bd37f5f462..7de733d5a35 100644
--- a/source/blender/functions/intern/lazy_function.cc
+++ b/source/blender/functions/intern/lazy_function.cc
@@ -36,30 +36,17 @@ void LazyFunction::destruct_storage(void *storage) const
UNUSED_VARS_NDEBUG(storage);
}
-bool LazyFunction::valid_params_for_execution(const Params ¶ms) const
+bool LazyFunction::always_used_inputs_available(const Params ¶ms) const
{
- bool all_required_inputs_available = true;
for (const int i : inputs_.index_range()) {
const Input &fn_input = inputs_[i];
if (fn_input.usage == ValueUsage::Used) {
if (params.try_get_input_data_ptr(i) == nullptr) {
- all_required_inputs_available = false;
- break;
+ return false;
}
}
}
- bool any_remaining_output_left = false;
- for (const int i : outputs_.index_range()) {
- if (params.get_output_usage(i) != ValueUsage::Unused) {
- if (!params.output_was_set(i)) {
- any_remaining_output_left = true;
- break;
- }
- }
- }
- BLI_assert(all_required_inputs_available);
- BLI_assert(any_remaining_output_left);
- return all_required_inputs_available && any_remaining_output_left;
+ return true;
}
void Params::set_default_remaining_outputs()
diff --git a/source/blender/functions/intern/lazy_function_graph_executor.cc b/source/blender/functions/intern/lazy_function_graph_executor.cc
index 20e9fbd52fc..69de1345e61 100644
--- a/source/blender/functions/intern/lazy_function_graph_executor.cc
+++ b/source/blender/functions/intern/lazy_function_graph_executor.cc
@@ -114,6 +114,11 @@ struct NodeState {
* Set to true once the node is done running for the first time.
*/
bool had_initialization = true;
+ /**
+ * Nodes with side effects should always be executed when their required inputs have been
+ * computed.
+ */
+ bool has_side_effects = false;
/**
* A node is always in one specific schedule state. This helps to ensure that the same node does
* not run twice at the same time accidentally.
@@ -170,12 +175,6 @@ class GraphExecutorLFParams;
class Executor {
private:
const LazyFunctionGraphExecutor &self_;
- /**
- * Usually nodes are only executed when at least one of their outputs are required.
- * Sometimes we want to execute nodes for their side effects though. So this is a list of all the
- * nodes that should be executed even when their outputs are not required.
- */
- Vector<const Node *> side_effect_nodes_;
/**
* Remembers which inputs have been loaded from the caller already, to avoid loading them twice.
* Atomics are used to make sure that every input is only retrieved once.
@@ -241,10 +240,8 @@ class Executor {
is_first_execution_ = false;
});
+ CurrentTask current_task;
if (is_first_execution_) {
- if (self_.side_effect_provider_ != nullptr) {
- side_effect_nodes_ = self_.side_effect_provider_->get_nodes_with_side_effects(context);
- }
this->initialize_node_states();
task_pool_ = BLI_task_pool_create(this, TASK_PRIORITY_HIGH);
@@ -253,9 +250,9 @@ class Executor {
this->set_always_unused_graph_inputs();
this->set_defaulted_graph_outputs();
+ this->schedule_side_effect_nodes(current_task);
}
- CurrentTask current_task;
this->schedule_newly_requested_outputs(current_task);
this->forward_newly_provided_inputs(current_task);
@@ -382,6 +379,21 @@ class Executor {
}
}
+ void schedule_side_effect_nodes(CurrentTask ¤t_task)
+ {
+ if (self_.side_effect_provider_ != nullptr) {
+ const Vector<const FunctionNode *> side_effect_nodes =
+ self_.side_effect_provider_->get_nodes_with_side_effects(*context_);
+ for (const FunctionNode *node : side_effect_nodes) {
+ NodeState &node_state = *node_states_[node->index_in_graph()];
+ node_state.has_side_effects = true;
+ this->with_locked_node(*node, node_state, current_task, [&](LockedNode &locked_node) {
+ this->schedule_node(locked_node);
+ });
+ }
+ }
+ }
+
void forward_newly_provided_inputs(CurrentTask ¤t_task)
{
LinearAllocator<> &allocator = local_allocators_.local();
@@ -588,7 +600,7 @@ class Executor {
required_uncomputed_output_exists = true;
}
}
- if (!required_uncomputed_output_exists) {
+ if (!required_uncomputed_output_exists && !node_state.has_side_effects) {
return;
}
@@ -686,13 +698,16 @@ class Executor {
NodeState &node_state = locked_node.node_state;
if (node_state.node_has_finished) {
+ /* Was finished already. */
return;
}
+ /* If there are outputs that may still be used, the node is not done yet. */
for (const OutputState &output_state : node_state.outputs) {
if (output_state.usage != ValueUsag
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list