34 using namespace fn::multi_function_types;
49 void *value =
nullptr;
67 int provided_value_count = 0;
71 return this->missing_values() == 0;
76 return this->values.
size() - this->provided_value_count;
81 const int index = this->find_available_index(origin);
82 this->values[index] = value;
83 this->provided_value_count++;
87 int find_available_index(
DSocket origin)
const
90 if (values[i] !=
nullptr) {
93 if (origins[i] != origin) {
140 bool was_ready_for_execution =
false;
146 bool force_compute =
false;
154 bool has_been_computed =
false;
177 int potential_users = 0;
224 bool non_lazy_inputs_handled =
false;
229 bool has_been_executed =
false;
236 bool node_has_finished =
false;
243 int missing_required_inputs = 0;
267 return a.node ==
b.node;
291 class GeometryNodesEvaluator;
329 if (
type ==
nullptr) {
333 if (!
type->has_special_member_functions()) {
352 if (node_declaration ==
nullptr) {
400 return node->typeinfo()->geometry_node_execute_supports_laziness;
421 bool can_get_input(
StringRef identifier)
const override;
422 bool can_set_output(
StringRef identifier)
const override;
428 void set_input_unused(
StringRef identifier)
override;
429 bool output_is_required(
StringRef identifier)
const override;
431 bool lazy_require_input(
StringRef identifier)
override;
432 bool lazy_output_is_required(
StringRef identifier)
const override;
434 void set_default_remaining_outputs()
override;
472 : outer_allocator_(
params.allocator),
482 this->create_states_for_reachable_nodes();
483 this->forward_group_inputs();
484 this->schedule_initial_nodes();
490 this->extract_group_outputs();
491 this->destruct_node_states();
508 while (!nodes_to_check.
is_empty()) {
521 input.foreach_origin_socket(
531 LinearAllocator<> &allocator = this->local_allocators_.local();
532 for (const NodeWithState &item : node_states_.as_span().slice(range)) {
533 this->initialize_node_state(item.node, *item.state, allocator);
541 node_state.
inputs[socket->
index()].force_compute =
true;
553 for (
const int i :
node->inputs().index_range()) {
558 input_state.
type =
nullptr;
564 if (
type ==
nullptr) {
586 for (
const int i :
node->outputs().index_range()) {
595 if (
type ==
nullptr) {
604 const DNode target_node = target_socket.
node();
605 if (!this->node_states_.
contains_as(target_node)) {
623 for (const NodeWithState &item : node_states_.as_span().slice(range)) {
624 this->destruct_node_state(item.node, *item.state);
632 for (
const int i :
node->inputs().index_range()) {
634 if (input_state.
type ==
nullptr) {
640 for (
void *value : multi_value.
values) {
641 if (value !=
nullptr) {
645 multi_value.~MultiInputValue();
649 void *value = single_value.
value;
650 if (value !=
nullptr) {
653 single_value.~SingleInputValue();
660 node_state.~NodeState();
672 this->log_socket_value({socket}, value);
676 this->forward_output(socket, value,
nullptr);
685 this->with_locked_node(
node, node_state,
nullptr, [&](
LockedNode &locked_node) {
687 this->set_input_required(locked_node, socket);
693 this->with_locked_node(
node, node_state,
nullptr, [&](
LockedNode &locked_node) {
695 this->set_input_required(locked_node, DInputSocket(socket));
698 OutputState &output_state = node_state.outputs[socket->index()];
699 output_state.output_usage = ValueUsage::Required;
700 this->schedule_node(locked_node);
747 DNode next_node_to_run = root_node_with_state->
node;
748 while (next_node_to_run) {
759 if (
node->is_group_input_node() ||
node->is_group_output_node()) {
765 const bool do_execute_node = this->node_task_preprocessing(
node, node_state, run_state);
769 if (do_execute_node) {
770 this->execute_node(
node, node_state, run_state);
773 this->node_task_postprocessing(
node, node_state, do_execute_node, run_state);
780 bool do_execute_node =
false;
781 this->with_locked_node(
node, node_state, run_state, [&](
LockedNode &locked_node) {
790 if (!this->prepare_node_outputs_for_execution(locked_node)) {
797 this->require_non_lazy_inputs(locked_node);
801 if (!this->prepare_node_inputs_for_execution(locked_node)) {
804 do_execute_node =
true;
806 return do_execute_node;
840 for (
const int i : locked_node.
node->
inputs().index_range()) {
844 this->set_input_unused(locked_node, socket);
849 this->destruct_input_value_if_exists(locked_node, socket);
858 bool execution_is_necessary =
false;
865 execution_is_necessary =
true;
869 return execution_is_necessary;
874 this->foreach_non_lazy_input(locked_node, [&](
const DInputSocket socket) {
875 this->set_input_required(locked_node, socket);
886 for (
const int i : locked_node.
node->
inputs().index_range()) {
888 if (input_state.
type ==
nullptr) {
906 if (input_state.
type ==
nullptr) {
924 else if (is_required) {
932 if (single_value.
value !=
nullptr) {
935 else if (is_required) {
964 this->execute_geometry_node(
node, node_state, run_state);
970 if (fn_item.
fn !=
nullptr) {
971 this->execute_multi_function_node(
node, fn_item, node_state, run_state);
975 this->execute_unknown_node(
node, node_state, run_state);
980 using Clock = std::chrono::steady_clock;
985 Clock::time_point begin = Clock::now();
987 Clock::time_point end = Clock::now();
988 const std::chrono::microseconds duration =
989 std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
1002 bool any_input_is_field =
false;
1005 for (
const int i :
node->inputs().index_range()) {
1018 input_types.
append(&field_cpp_type);
1020 any_input_is_field =
true;
1024 if (any_input_is_field) {
1025 this->execute_multi_function_node__field(
1026 node, fn_item, node_state, allocator, input_values, input_types, run_state);
1029 this->execute_multi_function_node__value(
1030 node, *fn_item.
fn, node_state, allocator, input_values, input_types, run_state);
1044 const void *input_value_or_field = input_values[i];
1046 input_fields.
append(field_cpp_type.
as_field(input_value_or_field));
1049 std::shared_ptr<fn::FieldOperation> operation;
1051 operation = std::make_shared<fn::FieldOperation>(fn_item.
owned_fn, std::move(input_fields));
1054 operation = std::make_shared<fn::FieldOperation>(*fn_item.
fn, std::move(input_fields));
1057 int output_index = 0;
1058 for (
const int i :
node->outputs().index_range()) {
1067 GField new_field{operation, output_index};
1070 this->forward_output(socket, {cpp_type,
buffer}, run_state);
1086 const void *input_value_or_field = input_values[i];
1089 const void *input_value = field_cpp_type.
get_value_ptr(input_value_or_field);
1094 for (
const int i :
node->outputs().index_range()) {
1097 output_buffers.
append({});
1103 void *value_or_field_buffer = allocator.
allocate(value_or_field_type->
size(),
1106 void *value_buffer = value_or_field_type->
get_value_ptr(value_or_field_buffer);
1109 output_buffers.
append({value_or_field_type, value_or_field_buffer});
1115 for (
const int i : output_buffers.
index_range()) {
1117 if (
buffer.get() ==
nullptr) {
1121 this->forward_output(socket,
buffer, run_state);
1136 if (
type ==
nullptr) {
1144 this->construct_default_value(*
type,
buffer);
1145 this->forward_output({
node.context(), socket}, {*
type,
buffer}, run_state);
1154 this->with_locked_node(
node, node_state, run_state, [&](
LockedNode &locked_node) {
1155 const bool node_has_finished = this->finish_node_if_possible(locked_node);
1159 if (reschedule_requested && !node_has_finished) {
1161 this->schedule_node(locked_node);
1164 this->assert_expected_outputs_have_been_computed(locked_node);
1187 if (supports_laziness) {
1218 void *value = single_value.
value;
1257 int missing_values = 0;
1264 if (single_value.
value ==
nullptr) {
1268 if (missing_values == 0) {
1278 [&](
const DSocket origin_socket) { origin_sockets.
append(origin_socket); });
1282 this->load_unlinked_input_value(locked_node, input_socket, input_state, input_socket);
1286 bool requested_from_other_node =
false;
1287 for (
const DSocket &origin_socket : origin_sockets) {
1291 this->load_unlinked_input_value(locked_node, input_socket, input_state, origin_socket);
1297 requested_from_other_node =
true;
1302 if (requested_from_other_node) {
1322 this->destruct_input_value_if_exists(locked_node, socket);
1347 this->with_locked_node(
node, node_state, run_state, [&](
LockedNode &locked_node) {
1355 this->schedule_node(locked_node);
1365 this->with_locked_node(
node, node_state, run_state, [&](
LockedNode &locked_node) {
1370 if (output_state.output_usage != ValueUsage::Required) {
1372 output_state.output_usage = ValueUsage::Unused;
1374 this->schedule_node(locked_node);
1386 task_pool_, run_node_from_task_pool, (
void *)node_with_state,
false,
nullptr);
1403 log_original_value_sockets.
append(from_socket);
1407 if (!this->should_forward_to_socket(to_socket)) {
1413 const DNode next_node = next_socket.
node();
1414 const bool is_last_socket = to_socket == next_socket;
1415 const bool do_conversion_if_necessary = is_last_socket ||
1419 if (do_conversion_if_necessary) {
1421 if (*current_value.
type() != next_type) {
1423 this->convert_value(*current_value.
type(), next_type, current_value.
get(),
buffer);
1424 if (current_value.
get() != value_to_forward.
get()) {
1427 current_value = {next_type,
buffer};
1430 if (current_value.
get() == value_to_forward.
get()) {
1432 log_original_value_sockets.
append(next_socket);
1438 this->log_socket_value({next_socket}, current_value);
1442 if (current_value.
get() == value_to_forward.
get()) {
1444 forward_original_value_sockets.
append(to_socket);
1448 this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state);
1451 this->log_socket_value(log_original_value_sockets, value_to_forward);
1452 this->forward_to_sockets_with_same_type(
1453 allocator, forward_original_value_sockets, value_to_forward, from_socket, run_state);
1460 if (target_node_with_state ==
nullptr) {
1467 std::lock_guard
lock{target_node_state.
mutex};
1469 return target_input_state.
usage != ValueUsage::Unused;
1482 else if (to_sockets.
size() == 1) {
1485 this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
1495 this->add_value_to_input_socket(to_socket, from_socket, {
type,
buffer}, run_state);
1499 this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
1514 this->with_locked_node(
node, node_state, run_state, [&](
LockedNode &locked_node) {
1517 MultiInputValue &multi_value = *input_state.value.multi;
1518 multi_value.add_value(origin, value.get());
1520 if (multi_value.all_values_available()) {
1521 this->log_socket_value({socket}, input_state, multi_value.values);
1531 if (input_state.
usage == ValueUsage::Required) {
1535 this->schedule_node(locked_node);
1562 this->log_socket_value({input_socket}, input_state, multi_value.
values);
1569 if (origin_socket != input_socket) {
1572 sockets_to_log_to.
append(origin_socket);
1576 this->log_socket_value(sockets_to_log_to, value);
1585 for (
void *&value : multi_value.
values) {
1586 if (value !=
nullptr) {
1595 if (single_value.
value !=
nullptr) {
1597 single_value.
value =
nullptr;
1610 if (
type == required_type) {
1614 this->convert_value(
type, required_type,
buffer, converted_buffer);
1616 return {required_type, converted_buffer};
1621 const void *from_value,
1632 if (from_field_type !=
nullptr && to_field_type !=
nullptr) {
1636 if (from_field_type->
is_field(from_value)) {
1639 conversions_.
try_convert(from_field, to_base_type));
1643 const void *from_value_ptr = from_field_type->
get_value_ptr(from_value);
1644 void *to_value_ptr = to_field_type->
get_value_ptr(to_value);
1657 this->construct_default_value(
to_type, to_value);
1663 type.value_initialize(r_value);
1680 for (
const void *value : values) {
1704 template<
typename Function>
1708 const Function &
function)
1712 node_state.
mutex.lock();
1716 node_state.
mutex.unlock();
1720 for (
const DOutputSocket &socket : locked_node.delayed_required_outputs) {
1721 this->send_output_required_notification(socket, run_state);
1723 for (
const DOutputSocket &socket : locked_node.delayed_unused_outputs) {
1724 this->send_output_unused_notification(socket, run_state);
1726 for (
const DNode &node_to_schedule : locked_node.delayed_scheduled_nodes) {
1736 this->add_node_to_task_pool(node_to_schedule);
1746 : evaluator_(evaluator), node_state_(node_state), run_state_(run_state)
1748 this->dnode =
dnode;
1770 return single_value.
value !=
nullptr;
1791 void *value = single_value.
value;
1792 single_value.
value =
nullptr;
1793 return {*input_state.
type, value};
1807 for (
void *&value : multi_value.
values) {
1809 ret_values.
append({*input_state.
type, value});
1824 return {*input_state.
type, single_value.
value};
1858 evaluator_.schedule_node(locked_node);
1903 for (
const int i : this->
dnode->
outputs().index_range()) {
1925 evaluator.execute();
#define GEO_NODE_SET_CURVE_HANDLES
#define GEO_NODE_EXTRUDE_MESH
#define FN_NODE_RANDOM_VALUE
#define GEO_NODE_INSTANCE_ON_POINTS
#define BLI_assert_unreachable()
void * BLI_task_pool_user_data(TaskPool *pool)
void BLI_task_pool_work_and_wait(TaskPool *pool)
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
void BLI_task_pool_free(TaskPool *pool)
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
@ GEO_NODE_CURVE_HANDLE_LEFT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
void copy_construct(const void *src, void *dst) const
void destruct(void *ptr) const
int64_t alignment() const
void default_construct(void *ptr) const
const CPPType * type() const
static GVArray ForSingleRef(const CPPType &type, int64_t size, const void *value)
destruct_ptr< T > construct(Args &&...args)
void * allocate(const int64_t size, const int64_t alignment)
MutableSpan< T > construct_array(int64_t size, Args &&...args)
constexpr Span drop_front(int64_t n) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void push(const T &value)
void add_new(const Key &key)
const Key & lookup_key_as(const ForwardKey &key) const
bool contains_as(const ForwardKey &key) const
const Key * lookup_key_ptr_as(const ForwardKey &key) const
void append(const T &value)
IndexRange index_range() const
void resize(const int64_t new_size)
void reserve(const int64_t min_capacity)
void convert_to_uninitialized(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value) const
const ConversionFunctions * get_conversion_functions(fn::MFDataType from, fn::MFDataType to) const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
GVArray try_convert(GVArray varray, const CPPType &to_type) const
virtual void call(IndexMask mask, MFParams params, MFContext context) const =0
const void * get_value_ptr(const void *value_or_field) const
void construct_from_field(void *dst, GField field) const
const CPPType & base_type() const
const GField * get_field_ptr(const void *value_or_field) const
GField as_field(const void *value_or_field) const
bool is_field(const void *value_or_field) const
void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
NodeState & get_node_state(const DNode node)
void destruct_node_states()
void require_non_lazy_inputs(LockedNode &locked_node)
void schedule_initial_nodes()
static void run_node_from_task_pool(TaskPool *task_pool, void *task_data)
void forward_to_sockets_with_same_type(LinearAllocator<> &allocator, Span< DInputSocket > to_sockets, GMutablePointer value_to_forward, const DOutputSocket from_socket, NodeTaskRunState *run_state)
void destruct_input_value_if_exists(LockedNode &locked_node, const DInputSocket socket)
GMutablePointer get_value_from_socket(const DSocket socket, const CPPType &required_type)
void with_locked_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state, const Function &function)
void node_task_run(const DNode node, NodeTaskRunState *run_state)
void log_debug_message(DNode node, std::string message)
void execute_multi_function_node__field(const DNode node, const nodes::NodeMultiFunctions::Item &fn_item, NodeState &node_state, LinearAllocator<> &allocator, Span< const void * > input_values, Span< const ValueOrFieldCPPType * > input_types, NodeTaskRunState *run_state)
void assert_expected_outputs_have_been_computed(LockedNode &locked_node)
void convert_value(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value)
void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator)
void extract_group_outputs()
GeometryNodesEvaluator(GeometryNodesEvaluationParams ¶ms)
void forward_group_inputs()
void load_unlinked_input_value(LockedNode &locked_node, const DInputSocket input_socket, InputState &input_state, const DSocket origin_socket)
bool should_forward_to_socket(const DInputSocket socket)
void add_value_to_input_socket(const DInputSocket socket, const DOutputSocket origin, GMutablePointer value, NodeTaskRunState *run_state)
void add_node_to_task_pool(const DNode node)
bool prepare_node_outputs_for_execution(LockedNode &locked_node)
void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
void execute_multi_function_node(const DNode node, const nodes::NodeMultiFunctions::Item &fn_item, NodeState &node_state, NodeTaskRunState *run_state)
bool set_input_required(LockedNode &locked_node, const DInputSocket input_socket)
void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
void execute_multi_function_node__value(const DNode node, const MultiFunction &fn, NodeState &node_state, LinearAllocator<> &allocator, Span< const void * > input_values, Span< const ValueOrFieldCPPType * > input_types, NodeTaskRunState *run_state)
void foreach_non_lazy_input(LockedNode &locked_node, FunctionRef< void(DInputSocket socket)> fn)
void destruct_node_state(const DNode node, NodeState &node_state)
bool prepare_node_inputs_for_execution(LockedNode &locked_node)
void forward_output(const DOutputSocket from_socket, GMutablePointer value_to_forward, NodeTaskRunState *run_state)
void create_states_for_reachable_nodes()
void log_socket_value(DSocket socket, InputState &input_state, Span< void * > values)
void send_output_unused_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
void construct_default_value(const CPPType &type, void *r_value)
void schedule_node(LockedNode &locked_node)
bool finish_node_if_possible(LockedNode &locked_node)
void node_task_postprocessing(const DNode node, NodeState &node_state, bool was_executed, NodeTaskRunState *run_state)
bool node_task_preprocessing(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
void log_socket_value(Span< DSocket > sockets, GPointer value)
void send_output_required_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
void set_input_unused(LockedNode &locked_node, const DInputSocket socket)
Vector< DOutputSocket > delayed_required_outputs
Vector< DNode > delayed_scheduled_nodes
Vector< DOutputSocket > delayed_unused_outputs
LockedNode(const DNode node, NodeState &node_state)
void set_input_unused(StringRef identifier) override
void set_output(StringRef identifier, GMutablePointer value) override
GPointer get_input(StringRef identifier) const override
bool lazy_output_is_required(StringRef identifier) const override
bool lazy_require_input(StringRef identifier) override
GMutablePointer alloc_output_value(const CPPType &type) override
void set_default_remaining_outputs() override
bool can_set_output(StringRef identifier) const override
Vector< GMutablePointer > extract_multi_input(StringRef identifier) override
GMutablePointer extract_input(StringRef identifier) override
bool can_get_input(StringRef identifier) const override
bool output_is_required(StringRef identifier) const override
DInputSocket input_by_identifier(StringRef identifier) const
DOutputSocket output(int index) const
DOutputSocket output_by_identifier(StringRef identifier) const
DInputSocket input(int index) const
void foreach_target_socket(ForeachTargetSocketFn target_fn) const
const SocketRef * socket_ref() const
const ModifierData * modifier
geometry_nodes_eval_log::GeoLogger * logger
const Object * self_object
Span< SocketDeclarationPtr > inputs() const
const Item & try_get(const DNode &node) const
Span< const InputSocketRef * > inputs() const
Span< const OutputSocketRef * > outputs() const
bool is_group_node() const
bool is_group_output_node() const
InputSocketFieldType input_field_type() const
const NodeRef & node() const
bNodeSocketType * typeinfo() const
bNodeSocket * bsocket() const
bool is_available() const
const InputSocketRef & as_input() const
void log_debug_message(DNode node, std::string message)
void log_multi_value_socket(DSocket socket, Span< GPointer > values)
void log_execution_time(DNode node, std::chrono::microseconds exec_time)
void log_value_for_sockets(Span< DSocket > sockets, GPointer value)
ccl_global float * buffer
ccl_global KernelShaderEvalInput * input
const DataTypeConversions & get_implicit_type_conversions()
static Type to_type(const eGPUType type)
static bool node_supports_laziness(const DNode node)
static const CPPType * get_socket_cpp_type(const DSocket socket)
static void get_socket_value(const SocketRef &socket, void *r_value)
static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
void evaluate_geometry_nodes(GeometryNodesEvaluationParams ¶ms)
static const CPPType * get_socket_cpp_type(const SocketRef &socket)
void isolate_task(const Function &function)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
std::chrono::steady_clock Clock
void destruct_n(T *ptr, int64_t n)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
unsigned __int64 uint64_t
SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value
const CPPTypeHandle * geometry_nodes_cpp_type
NodeGeometryExecFunction geometry_node_execute
struct bNodeType * typeinfo
void(* convert_single_to_initialized)(const void *src, void *dst)
Vector< DInputSocket > output_sockets
Map< DOutputSocket, GMutablePointer > input_values
Vector< GMutablePointer > r_output_values
const NodesModifierData * modifier_
nodes::NodeMultiFunctions * mf_by_node
Vector< DSocket > force_compute_sockets
geo_log::GeoLogger * geo_logger
MutableSpan< OutputState > outputs
bool non_lazy_inputs_handled
NodeScheduleState schedule_state
int missing_required_inputs
MutableSpan< InputState > inputs
static uint64_t hash_as(const DNode &node)
friend bool operator==(const NodeWithState &a, const DNode &b)
friend bool operator==(const DNode &a, const NodeWithState &b)
friend bool operator==(const NodeWithState &a, const NodeWithState &b)
ValueUsage output_usage_for_execution
Vector< DSocket, 16 > sockets
std::shared_ptr< MultiFunction > owned_fn