Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_nodes.cc
| Show First 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | static bool isDisabled(const struct Scene *UNUSED(scene), | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| class GeometryNodesEvaluator { | class GeometryNodesEvaluator { | ||||
| private: | private: | ||||
| blender::LinearAllocator<> allocator_; | blender::LinearAllocator<> allocator_; | ||||
| Map<const DInputSocket *, GMutablePointer> value_by_input_; | Map<std::pair<const DInputSocket *, const DOutputSocket *>, GMutablePointer> value_by_input_; | ||||
| Vector<const DInputSocket *> group_outputs_; | Vector<const DInputSocket *> group_outputs_; | ||||
| blender::nodes::MultiFunctionByNode &mf_by_node_; | blender::nodes::MultiFunctionByNode &mf_by_node_; | ||||
| const blender::nodes::DataTypeConversions &conversions_; | const blender::nodes::DataTypeConversions &conversions_; | ||||
| const PersistentDataHandleMap &handle_map_; | const PersistentDataHandleMap &handle_map_; | ||||
| const Object *self_object_; | const Object *self_object_; | ||||
| Depsgraph *depsgraph_; | |||||
| public: | public: | ||||
| GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data, | GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data, | ||||
| Vector<const DInputSocket *> group_outputs, | Vector<const DInputSocket *> group_outputs, | ||||
| blender::nodes::MultiFunctionByNode &mf_by_node, | blender::nodes::MultiFunctionByNode &mf_by_node, | ||||
| const PersistentDataHandleMap &handle_map, | const PersistentDataHandleMap &handle_map, | ||||
| const Object *self_object) | const Object *self_object, | ||||
| Depsgraph *depsgraph) | |||||
| : group_outputs_(std::move(group_outputs)), | : group_outputs_(std::move(group_outputs)), | ||||
| mf_by_node_(mf_by_node), | mf_by_node_(mf_by_node), | ||||
| conversions_(blender::nodes::get_implicit_type_conversions()), | conversions_(blender::nodes::get_implicit_type_conversions()), | ||||
| handle_map_(handle_map), | handle_map_(handle_map), | ||||
| self_object_(self_object) | self_object_(self_object), | ||||
| depsgraph_(depsgraph) | |||||
| { | { | ||||
| for (auto item : group_input_data.items()) { | for (auto item : group_input_data.items()) { | ||||
| this->forward_to_inputs(*item.key, item.value); | this->forward_to_inputs(*item.key, item.value); | ||||
| } | } | ||||
| } | } | ||||
| Vector<GMutablePointer> execute() | Vector<GMutablePointer> execute() | ||||
| { | { | ||||
| Vector<GMutablePointer> results; | Vector<GMutablePointer> results; | ||||
| for (const DInputSocket *group_output : group_outputs_) { | for (const DInputSocket *group_output : group_outputs_) { | ||||
| GMutablePointer result = this->get_input_value(*group_output); | Vector<GMutablePointer> result = this->get_input_values(*group_output); | ||||
| results.append(result); | results.append(result[0]); | ||||
| } | } | ||||
| for (GMutablePointer value : value_by_input_.values()) { | for (GMutablePointer value : value_by_input_.values()) { | ||||
| value.destruct(); | value.destruct(); | ||||
| } | } | ||||
| return results; | return results; | ||||
| } | } | ||||
| private: | private: | ||||
| GMutablePointer get_input_value(const DInputSocket &socket_to_compute) | Vector<GMutablePointer> get_input_values(const DInputSocket &socket_to_compute) | ||||
| { | { | ||||
| std::optional<GMutablePointer> value = value_by_input_.pop_try(&socket_to_compute); | |||||
| if (value.has_value()) { | |||||
| /* This input has been computed before, return it directly. */ | |||||
| return *value; | |||||
| } | |||||
| Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets(); | Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets(); | ||||
| Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs(); | Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs(); | ||||
| const int total_inputs = from_sockets.size() + from_group_inputs.size(); | const int total_inputs = from_sockets.size() + from_group_inputs.size(); | ||||
| BLI_assert(total_inputs <= 1); | |||||
| if (total_inputs == 0) { | if (total_inputs == 0) { | ||||
| /* The input is not connected, use the value from the socket itself. */ | /* The input is not connected, use the value from the socket itself. */ | ||||
| return get_unlinked_input_value(socket_to_compute); | return {get_unlinked_input_value(socket_to_compute)}; | ||||
| } | } | ||||
| if (from_group_inputs.size() == 1) { | if (from_group_inputs.size() == 1) { | ||||
| /* The input gets its value from the input of a group that is not further connected. */ | return {get_unlinked_input_value(socket_to_compute)}; | ||||
| return get_unlinked_input_value(socket_to_compute); | } | ||||
| /* Multi-input sockets contain a vector of inputs. */ | |||||
| if (socket_to_compute.is_multi_input_socket()) { | |||||
| Vector<GMutablePointer> values; | |||||
| for (const DOutputSocket *from_socket : from_sockets) { | |||||
| const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( | |||||
| &socket_to_compute, from_socket); | |||||
| std::optional<GMutablePointer> value = value_by_input_.pop_try(key); | |||||
| if (value.has_value()) { | |||||
| values.append(*value); | |||||
| } | |||||
| else { | |||||
| this->compute_output_and_forward(*from_socket); | |||||
| GMutablePointer value = value_by_input_.pop(key); | |||||
| values.append(value); | |||||
| } | |||||
| } | |||||
| return values; | |||||
| } | } | ||||
| /* Compute the socket now. */ | |||||
| const DOutputSocket &from_socket = *from_sockets[0]; | const DOutputSocket &from_socket = *from_sockets[0]; | ||||
| const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( | |||||
| &socket_to_compute, &from_socket); | |||||
| std::optional<GMutablePointer> value = value_by_input_.pop_try(key); | |||||
| if (value.has_value()) { | |||||
| /* This input has been computed before, return it directly. */ | |||||
| return {*value}; | |||||
| } | |||||
| /* Compute the socket now. */ | |||||
| this->compute_output_and_forward(from_socket); | this->compute_output_and_forward(from_socket); | ||||
| return value_by_input_.pop(&socket_to_compute); | return {value_by_input_.pop(key)}; | ||||
| } | } | ||||
| void compute_output_and_forward(const DOutputSocket &socket_to_compute) | void compute_output_and_forward(const DOutputSocket &socket_to_compute) | ||||
| { | { | ||||
| const DNode &node = socket_to_compute.node(); | const DNode &node = socket_to_compute.node(); | ||||
| const bNode &bnode = *node.bnode(); | const bNode &bnode = *node.bnode(); | ||||
| if (!socket_to_compute.is_available()) { | if (!socket_to_compute.is_available()) { | ||||
| /* If the output is not available, use a default value. */ | /* If the output is not available, use a default value. */ | ||||
| const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo()); | const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo()); | ||||
| void *buffer = allocator_.allocate(type.size(), type.alignment()); | void *buffer = allocator_.allocate(type.size(), type.alignment()); | ||||
| type.copy_to_uninitialized(type.default_value(), buffer); | type.copy_to_uninitialized(type.default_value(), buffer); | ||||
| this->forward_to_inputs(socket_to_compute, {type, buffer}); | this->forward_to_inputs(socket_to_compute, {type, buffer}); | ||||
| return; | return; | ||||
| } | } | ||||
| /* Prepare inputs required to execute the node. */ | /* Prepare inputs required to execute the node. */ | ||||
| GValueMap<StringRef> node_inputs_map{allocator_}; | GValueMap<StringRef> node_inputs_map{allocator_}; | ||||
| for (const DInputSocket *input_socket : node.inputs()) { | for (const DInputSocket *input_socket : node.inputs()) { | ||||
| if (input_socket->is_available()) { | if (input_socket->is_available()) { | ||||
| GMutablePointer value = this->get_input_value(*input_socket); | Vector<GMutablePointer> values = this->get_input_values(*input_socket); | ||||
| node_inputs_map.add_new_direct(input_socket->identifier(), value); | for (int i = 0; i < values.size(); ++i) { | ||||
| /* Values from Multi Input Sockets are stored in input map with the format | |||||
| * <identifier>[<index>]. */ | |||||
| blender::StringRefNull key = allocator_.copy_string( | |||||
| input_socket->identifier() + (i > 0 ? ("[" + std::to_string(i)) + "]" : "")); | |||||
| node_inputs_map.add_new_direct(key, std::move(values[i])); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| /* Execute the node. */ | /* Execute the node. */ | ||||
| GValueMap<StringRef> node_outputs_map{allocator_}; | GValueMap<StringRef> node_outputs_map{allocator_}; | ||||
| GeoNodeExecParams params{bnode, node_inputs_map, node_outputs_map, handle_map_, self_object_}; | GeoNodeExecParams params{ | ||||
| bnode, node_inputs_map, node_outputs_map, handle_map_, self_object_, depsgraph_}; | |||||
| this->execute_node(node, params); | this->execute_node(node, params); | ||||
| /* Forward computed outputs to linked input sockets. */ | /* Forward computed outputs to linked input sockets. */ | ||||
| for (const DOutputSocket *output_socket : node.outputs()) { | for (const DOutputSocket *output_socket : node.outputs()) { | ||||
| if (output_socket->is_available()) { | if (output_socket->is_available()) { | ||||
| GMutablePointer value = node_outputs_map.extract(output_socket->identifier()); | GMutablePointer value = node_outputs_map.extract(output_socket->identifier()); | ||||
| this->forward_to_inputs(*output_socket, value); | this->forward_to_inputs(*output_socket, value); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | for (const DOutputSocket *socket : node.outputs()) { | ||||
| const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); | const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); | ||||
| params.set_output_by_copy(socket->identifier(), {type, type.default_value()}); | params.set_output_by_copy(socket->identifier(), {type, type.default_value()}); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward) | void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward) | ||||
| { | { | ||||
| /* For all sockets that are linked with the from_socket push the value to their node. */ | |||||
| Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets(); | Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets(); | ||||
| const CPPType &from_type = *value_to_forward.type(); | const CPPType &from_type = *value_to_forward.type(); | ||||
| Vector<const DInputSocket *> to_sockets_same_type; | Vector<const DInputSocket *> to_sockets_same_type; | ||||
| for (const DInputSocket *to_socket : to_sockets_all) { | for (const DInputSocket *to_socket : to_sockets_all) { | ||||
| const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo()); | const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo()); | ||||
| const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( | |||||
| to_socket, &from_socket); | |||||
| if (from_type == to_type) { | if (from_type == to_type) { | ||||
| to_sockets_same_type.append(to_socket); | to_sockets_same_type.append(to_socket); | ||||
| } | } | ||||
| else { | else { | ||||
| void *buffer = allocator_.allocate(to_type.size(), to_type.alignment()); | void *buffer = allocator_.allocate(to_type.size(), to_type.alignment()); | ||||
| if (conversions_.is_convertible(from_type, to_type)) { | if (conversions_.is_convertible(from_type, to_type)) { | ||||
| conversions_.convert(from_type, to_type, value_to_forward.get(), buffer); | conversions_.convert(from_type, to_type, value_to_forward.get(), buffer); | ||||
| } | } | ||||
| else { | else { | ||||
| to_type.copy_to_uninitialized(to_type.default_value(), buffer); | to_type.copy_to_uninitialized(to_type.default_value(), buffer); | ||||
| } | } | ||||
| value_by_input_.add_new(to_socket, GMutablePointer{to_type, buffer}); | add_value_to_input_socket(key, GMutablePointer{to_type, buffer}); | ||||
| } | } | ||||
| } | } | ||||
| if (to_sockets_same_type.size() == 0) { | if (to_sockets_same_type.size() == 0) { | ||||
| /* This value is not further used, so destruct it. */ | /* This value is not further used, so destruct it. */ | ||||
| value_to_forward.destruct(); | value_to_forward.destruct(); | ||||
| } | } | ||||
| else if (to_sockets_same_type.size() == 1) { | else if (to_sockets_same_type.size() == 1) { | ||||
| /* This value is only used on one input socket, no need to copy it. */ | /* This value is only used on one input socket, no need to copy it. */ | ||||
| const DInputSocket *to_socket = to_sockets_same_type[0]; | const DInputSocket *to_socket = to_sockets_same_type[0]; | ||||
| value_by_input_.add_new(to_socket, value_to_forward); | const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( | ||||
| to_socket, &from_socket); | |||||
| add_value_to_input_socket(key, value_to_forward); | |||||
| } | } | ||||
| else { | else { | ||||
| /* Multiple inputs use the value, make a copy for every input except for one. */ | /* Multiple inputs use the value, make a copy for every input except for one. */ | ||||
| const DInputSocket *first_to_socket = to_sockets_same_type[0]; | const DInputSocket *first_to_socket = to_sockets_same_type[0]; | ||||
| Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1); | Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1); | ||||
| const CPPType &type = *value_to_forward.type(); | const CPPType &type = *value_to_forward.type(); | ||||
| const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair( | |||||
| value_by_input_.add_new(first_to_socket, value_to_forward); | first_to_socket, &from_socket); | ||||
| add_value_to_input_socket(first_key, value_to_forward); | |||||
| for (const DInputSocket *to_socket : other_to_sockets) { | for (const DInputSocket *to_socket : other_to_sockets) { | ||||
| const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( | |||||
| to_socket, &from_socket); | |||||
| void *buffer = allocator_.allocate(type.size(), type.alignment()); | void *buffer = allocator_.allocate(type.size(), type.alignment()); | ||||
| type.copy_to_uninitialized(value_to_forward.get(), buffer); | type.copy_to_uninitialized(value_to_forward.get(), buffer); | ||||
| value_by_input_.add_new(to_socket, GMutablePointer{type, buffer}); | add_value_to_input_socket(key, GMutablePointer{type, buffer}); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void add_value_to_input_socket(const std::pair<const DInputSocket *, const DOutputSocket *> key, | |||||
| GMutablePointer value) | |||||
| { | |||||
| value_by_input_.add_new(key, value); | |||||
| } | |||||
| GMutablePointer get_unlinked_input_value(const DInputSocket &socket) | GMutablePointer get_unlinked_input_value(const DInputSocket &socket) | ||||
| { | { | ||||
| bNodeSocket *bsocket; | bNodeSocket *bsocket; | ||||
| if (socket.linked_group_inputs().size() == 0) { | if (socket.linked_group_inputs().size() == 0) { | ||||
| bsocket = socket.bsocket(); | bsocket = socket.bsocket(); | ||||
| } | } | ||||
| else { | else { | ||||
| bsocket = socket.linked_group_inputs()[0]->bsocket(); | bsocket = socket.linked_group_inputs()[0]->bsocket(); | ||||
| ▲ Show 20 Lines • Show All 475 Lines • ▼ Show 20 Lines | for (const DOutputSocket *socket : remaining_input_sockets) { | ||||
| group_inputs.add_new(socket, {cpp_type, value_in}); | group_inputs.add_new(socket, {cpp_type, value_in}); | ||||
| } | } | ||||
| } | } | ||||
| Vector<const DInputSocket *> group_outputs; | Vector<const DInputSocket *> group_outputs; | ||||
| group_outputs.append(&socket_to_compute); | group_outputs.append(&socket_to_compute); | ||||
| GeometryNodesEvaluator evaluator{ | GeometryNodesEvaluator evaluator{ | ||||
| group_inputs, group_outputs, mf_by_node, handle_map, ctx->object}; | group_inputs, group_outputs, mf_by_node, handle_map, ctx->object, ctx->depsgraph}; | ||||
| Vector<GMutablePointer> results = evaluator.execute(); | Vector<GMutablePointer> results = evaluator.execute(); | ||||
| BLI_assert(results.size() == 1); | BLI_assert(results.size() == 1); | ||||
| GMutablePointer result = results[0]; | GMutablePointer result = results[0]; | ||||
| GeometrySet output_geometry = std::move(*(GeometrySet *)result.get()); | GeometrySet output_geometry = std::move(*(GeometrySet *)result.get()); | ||||
| return output_geometry; | return output_geometry; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 288 Lines • Show Last 20 Lines | |||||