|
|
|
@ -18,6 +18,8 @@
|
|
|
|
|
#include "NOD_multi_function.hh"
|
|
|
|
|
#include "NOD_node_declaration.hh"
|
|
|
|
|
|
|
|
|
|
#include "BLI_bit_array_vector.hh"
|
|
|
|
|
#include "BLI_bit_span_ops.hh"
|
|
|
|
|
#include "BLI_cpp_types.hh"
|
|
|
|
|
#include "BLI_dot_export.hh"
|
|
|
|
|
#include "BLI_hash.h"
|
|
|
|
@ -2298,15 +2300,21 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
this->build_attribute_references(
|
|
|
|
|
relations_by_node, attribute_reference_keys, attribute_reference_infos);
|
|
|
|
|
|
|
|
|
|
MultiValueMap<const bNodeSocket *, int> referenced_by_field_socket;
|
|
|
|
|
MultiValueMap<const bNodeSocket *, int> propagated_to_geometry_socket;
|
|
|
|
|
const int sockets_num = btree_.all_sockets().size();
|
|
|
|
|
const int attribute_references_num = attribute_reference_keys.size();
|
|
|
|
|
|
|
|
|
|
/* The code below uses #BitArrayVector to store a set of attribute references per socket. Each
|
|
|
|
|
* socket has a bit span where each bit corresponds to one attribute reference. */
|
|
|
|
|
BitArrayVector<> referenced_by_field_socket(sockets_num, attribute_references_num, false);
|
|
|
|
|
BitArrayVector<> propagated_to_geometry_socket(sockets_num, attribute_references_num, false);
|
|
|
|
|
this->gather_referenced_and_potentially_propagated_data(relations_by_node,
|
|
|
|
|
attribute_reference_keys,
|
|
|
|
|
attribute_reference_infos,
|
|
|
|
|
referenced_by_field_socket,
|
|
|
|
|
propagated_to_geometry_socket);
|
|
|
|
|
|
|
|
|
|
MultiValueMap<const bNodeSocket *, int> required_propagated_to_geometry_socket;
|
|
|
|
|
BitArrayVector<> required_propagated_to_geometry_socket(
|
|
|
|
|
sockets_num, attribute_references_num, false);
|
|
|
|
|
this->gather_required_propagated_data(relations_by_node,
|
|
|
|
|
attribute_reference_keys,
|
|
|
|
|
referenced_by_field_socket,
|
|
|
|
@ -2407,10 +2415,10 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
const Span<const aal::RelationsInNode *> relations_by_node,
|
|
|
|
|
const Span<AttributeReferenceKey> attribute_reference_keys,
|
|
|
|
|
const Span<AttributeReferenceInfo> attribute_reference_infos,
|
|
|
|
|
MultiValueMap<const bNodeSocket *, int> &r_referenced_by_field_socket,
|
|
|
|
|
MultiValueMap<const bNodeSocket *, int> &r_propagated_to_geometry_socket)
|
|
|
|
|
BitArrayVector<> &r_referenced_by_field_socket,
|
|
|
|
|
BitArrayVector<> &r_propagated_to_geometry_socket)
|
|
|
|
|
{
|
|
|
|
|
/* Initialize maps. */
|
|
|
|
|
/* Insert initial referenced/propagated attributes. */
|
|
|
|
|
for (const int key_index : attribute_reference_keys.index_range()) {
|
|
|
|
|
const AttributeReferenceKey &key = attribute_reference_keys[key_index];
|
|
|
|
|
const AttributeReferenceInfo &info = attribute_reference_infos[key_index];
|
|
|
|
@ -2418,7 +2426,7 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
case AttributeReferenceKeyType::InputField: {
|
|
|
|
|
for (const bNode *bnode : btree_.group_input_nodes()) {
|
|
|
|
|
const bNodeSocket &bsocket = bnode->output_socket(key.index);
|
|
|
|
|
r_referenced_by_field_socket.add(&bsocket, key_index);
|
|
|
|
|
r_referenced_by_field_socket[bsocket.index_in_tree()][key_index].set();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -2426,34 +2434,28 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case AttributeReferenceKeyType::Socket: {
|
|
|
|
|
r_referenced_by_field_socket.add(key.bsocket, key_index);
|
|
|
|
|
r_referenced_by_field_socket[key.bsocket->index_in_tree()][key_index].set();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const bNodeSocket *geometry_bsocket : info.initial_geometry_sockets) {
|
|
|
|
|
r_propagated_to_geometry_socket.add(geometry_bsocket, key_index);
|
|
|
|
|
r_propagated_to_geometry_socket[geometry_bsocket->index_in_tree()][key_index].set();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Propagate attribute usages from left to right. */
|
|
|
|
|
for (const bNode *bnode : btree_.toposort_left_to_right()) {
|
|
|
|
|
for (const bNodeSocket *bsocket : bnode->input_sockets()) {
|
|
|
|
|
if (bsocket->is_available()) {
|
|
|
|
|
Vector<int> referenced_keys;
|
|
|
|
|
Vector<int> propagated_keys;
|
|
|
|
|
const int dst_index = bsocket->index_in_tree();
|
|
|
|
|
MutableBoundedBitSpan referenced_dst = r_referenced_by_field_socket[dst_index];
|
|
|
|
|
MutableBoundedBitSpan propagated_dst = r_propagated_to_geometry_socket[dst_index];
|
|
|
|
|
for (const bNodeLink *blink : bsocket->directly_linked_links()) {
|
|
|
|
|
if (blink->is_used()) {
|
|
|
|
|
referenced_keys.extend_non_duplicates(
|
|
|
|
|
r_referenced_by_field_socket.lookup(blink->fromsock));
|
|
|
|
|
propagated_keys.extend_non_duplicates(
|
|
|
|
|
r_propagated_to_geometry_socket.lookup(blink->fromsock));
|
|
|
|
|
const int src_index = blink->fromsock->index_in_tree();
|
|
|
|
|
referenced_dst |= r_referenced_by_field_socket[src_index];
|
|
|
|
|
propagated_dst |= r_propagated_to_geometry_socket[src_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!referenced_keys.is_empty()) {
|
|
|
|
|
r_referenced_by_field_socket.add_multiple(bsocket, referenced_keys);
|
|
|
|
|
}
|
|
|
|
|
if (!propagated_keys.is_empty()) {
|
|
|
|
|
r_propagated_to_geometry_socket.add_multiple(bsocket, propagated_keys);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const aal::RelationsInNode &relations = *relations_by_node[bnode->index()];
|
|
|
|
@ -2463,8 +2465,8 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
if (!input_bsocket.is_available() || !output_bsocket.is_available()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
r_referenced_by_field_socket.add_multiple(
|
|
|
|
|
&output_bsocket, Vector<int>(r_referenced_by_field_socket.lookup(&input_bsocket)));
|
|
|
|
|
r_referenced_by_field_socket[output_bsocket.index_in_tree()] |=
|
|
|
|
|
r_referenced_by_field_socket[input_bsocket.index_in_tree()];
|
|
|
|
|
}
|
|
|
|
|
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
|
|
|
|
|
const bNodeSocket &input_bsocket = bnode->input_socket(relation.from_geometry_input);
|
|
|
|
@ -2472,8 +2474,8 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
if (!input_bsocket.is_available() || !output_bsocket.is_available()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
r_propagated_to_geometry_socket.add_multiple(
|
|
|
|
|
&output_bsocket, Vector<int>(r_propagated_to_geometry_socket.lookup(&input_bsocket)));
|
|
|
|
|
r_propagated_to_geometry_socket[output_bsocket.index_in_tree()] |=
|
|
|
|
|
r_propagated_to_geometry_socket[input_bsocket.index_in_tree()];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2484,12 +2486,14 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
void gather_required_propagated_data(
|
|
|
|
|
const Span<const aal::RelationsInNode *> relations_by_node,
|
|
|
|
|
const VectorSet<AttributeReferenceKey> &attribute_reference_keys,
|
|
|
|
|
const MultiValueMap<const bNodeSocket *, int> &referenced_by_field_socket,
|
|
|
|
|
const MultiValueMap<const bNodeSocket *, int> &propagated_to_geometry_socket,
|
|
|
|
|
MultiValueMap<const bNodeSocket *, int> &r_required_propagated_to_geometry_socket)
|
|
|
|
|
const BitArrayVector<> &referenced_by_field_socket,
|
|
|
|
|
const BitArrayVector<> &propagated_to_geometry_socket,
|
|
|
|
|
BitArrayVector<> &r_required_propagated_to_geometry_socket)
|
|
|
|
|
{
|
|
|
|
|
const aal::RelationsInNode &tree_relations = *btree_.runtime->anonymous_attribute_relations;
|
|
|
|
|
MultiValueMap<const bNodeSocket *, int> required_by_geometry_socket;
|
|
|
|
|
const int sockets_num = btree_.all_sockets().size();
|
|
|
|
|
const int attribute_references_num = referenced_by_field_socket.group_size();
|
|
|
|
|
BitArrayVector<> required_by_geometry_socket(sockets_num, attribute_references_num, false);
|
|
|
|
|
|
|
|
|
|
/* Initialize required attributes at group output. */
|
|
|
|
|
if (const bNode *group_output_bnode = btree_.group_output_node()) {
|
|
|
|
@ -2498,74 +2502,66 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
key.type = AttributeReferenceKeyType::OutputGeometry;
|
|
|
|
|
key.index = relation.to_geometry_output;
|
|
|
|
|
const int key_index = attribute_reference_keys.index_of(key);
|
|
|
|
|
required_by_geometry_socket.add(
|
|
|
|
|
&group_output_bnode->input_socket(relation.to_geometry_output), key_index);
|
|
|
|
|
required_by_geometry_socket[group_output_bnode->input_socket(relation.to_geometry_output)
|
|
|
|
|
.index_in_tree()][key_index]
|
|
|
|
|
.set();
|
|
|
|
|
}
|
|
|
|
|
for (const aal::AvailableRelation &relation : tree_relations.available_relations) {
|
|
|
|
|
const bNodeSocket &geometry_bsocket = group_output_bnode->input_socket(
|
|
|
|
|
relation.geometry_output);
|
|
|
|
|
const bNodeSocket &field_bsocket = group_output_bnode->input_socket(relation.field_output);
|
|
|
|
|
required_by_geometry_socket.add_multiple(
|
|
|
|
|
&geometry_bsocket, referenced_by_field_socket.lookup(&field_bsocket));
|
|
|
|
|
required_by_geometry_socket[geometry_bsocket.index_in_tree()] |=
|
|
|
|
|
referenced_by_field_socket[field_bsocket.index_in_tree()];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Propagate attribute usages from right to left. */
|
|
|
|
|
BitVector<> required_attributes(attribute_references_num);
|
|
|
|
|
for (const bNode *bnode : btree_.toposort_right_to_left()) {
|
|
|
|
|
const aal::RelationsInNode &relations = *relations_by_node[bnode->index()];
|
|
|
|
|
for (const bNodeSocket *bsocket : bnode->output_sockets()) {
|
|
|
|
|
if (!bsocket->is_available()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Vector<int> required_attributes;
|
|
|
|
|
required_attributes.fill(false);
|
|
|
|
|
for (const bNodeLink *blink : bsocket->directly_linked_links()) {
|
|
|
|
|
if (blink->is_used()) {
|
|
|
|
|
const bNodeSocket &to_socket = *blink->tosock;
|
|
|
|
|
required_attributes.extend_non_duplicates(
|
|
|
|
|
required_by_geometry_socket.lookup(&to_socket));
|
|
|
|
|
required_attributes |= required_by_geometry_socket[to_socket.index_in_tree()];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const Span<int> available_attributes = propagated_to_geometry_socket.lookup(bsocket);
|
|
|
|
|
for (const int key_index : required_attributes) {
|
|
|
|
|
if (available_attributes.contains(key_index)) {
|
|
|
|
|
required_by_geometry_socket.add(bsocket, key_index);
|
|
|
|
|
|
|
|
|
|
const AttributeReferenceKey &key = attribute_reference_keys[key_index];
|
|
|
|
|
if (key.type != AttributeReferenceKeyType::Socket ||
|
|
|
|
|
&key.bsocket->owner_node() != bnode) {
|
|
|
|
|
r_required_propagated_to_geometry_socket.add(bsocket, key_index);
|
|
|
|
|
}
|
|
|
|
|
required_attributes &= propagated_to_geometry_socket[bsocket->index_in_tree()];
|
|
|
|
|
required_by_geometry_socket[bsocket->index_in_tree()] |= required_attributes;
|
|
|
|
|
bits::foreach_1_index(required_attributes, [&](const int key_index) {
|
|
|
|
|
const AttributeReferenceKey &key = attribute_reference_keys[key_index];
|
|
|
|
|
if (key.type != AttributeReferenceKeyType::Socket ||
|
|
|
|
|
&key.bsocket->owner_node() != bnode) {
|
|
|
|
|
r_required_propagated_to_geometry_socket[bsocket->index_in_tree()][key_index].set();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const bNodeSocket *bsocket : bnode->input_sockets()) {
|
|
|
|
|
if (!bsocket->is_available()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Vector<int> required_attributes;
|
|
|
|
|
required_attributes.fill(false);
|
|
|
|
|
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
|
|
|
|
|
if (relation.from_geometry_input == bsocket->index()) {
|
|
|
|
|
const bNodeSocket &output_bsocket = bnode->output_socket(relation.to_geometry_output);
|
|
|
|
|
required_attributes.extend_non_duplicates(
|
|
|
|
|
required_by_geometry_socket.lookup(&output_bsocket));
|
|
|
|
|
required_attributes |= required_by_geometry_socket[output_bsocket.index_in_tree()];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const aal::EvalRelation &relation : relations.eval_relations) {
|
|
|
|
|
if (relation.geometry_input == bsocket->index()) {
|
|
|
|
|
const bNodeSocket &field_bsocket = bnode->input_socket(relation.field_input);
|
|
|
|
|
if (field_bsocket.is_available()) {
|
|
|
|
|
required_attributes.extend_non_duplicates(
|
|
|
|
|
referenced_by_field_socket.lookup(&field_bsocket));
|
|
|
|
|
required_attributes |= referenced_by_field_socket[field_bsocket.index_in_tree()];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const Span<int> available_attributes = propagated_to_geometry_socket.lookup(bsocket);
|
|
|
|
|
for (const int key_index : required_attributes) {
|
|
|
|
|
if (available_attributes.contains(key_index)) {
|
|
|
|
|
required_by_geometry_socket.add(bsocket, key_index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
required_attributes &= propagated_to_geometry_socket[bsocket->index_in_tree()];
|
|
|
|
|
required_by_geometry_socket[bsocket->index_in_tree()] |= required_attributes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2577,20 +2573,19 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
void build_attribute_sets_to_propagate(
|
|
|
|
|
const Span<AttributeReferenceKey> attribute_reference_keys,
|
|
|
|
|
const Span<AttributeReferenceInfo> attribute_reference_infos,
|
|
|
|
|
const MultiValueMap<const bNodeSocket *, int> &required_propagated_to_geometry_socket)
|
|
|
|
|
const BitArrayVector<> &required_propagated_to_geometry_socket)
|
|
|
|
|
{
|
|
|
|
|
JoinAttibuteSetsCache join_attribute_sets_cache;
|
|
|
|
|
|
|
|
|
|
for (const auto [geometry_output_bsocket, lf_attribute_set_input] :
|
|
|
|
|
attribute_set_propagation_map_.items()) {
|
|
|
|
|
const Span<int> required = required_propagated_to_geometry_socket.lookup(
|
|
|
|
|
geometry_output_bsocket);
|
|
|
|
|
const BoundedBitSpan required =
|
|
|
|
|
required_propagated_to_geometry_socket[geometry_output_bsocket->index_in_tree()];
|
|
|
|
|
|
|
|
|
|
Vector<lf::OutputSocket *> attribute_set_sockets;
|
|
|
|
|
Vector<lf::OutputSocket *> used_sockets;
|
|
|
|
|
|
|
|
|
|
for (const int i : required.index_range()) {
|
|
|
|
|
const int key_index = required[i];
|
|
|
|
|
bits::foreach_1_index(required, [&](const int key_index) {
|
|
|
|
|
const AttributeReferenceKey &key = attribute_reference_keys[key_index];
|
|
|
|
|
const AttributeReferenceInfo &info = attribute_reference_infos[key_index];
|
|
|
|
|
lf::OutputSocket *lf_socket_usage = nullptr;
|
|
|
|
@ -2615,7 +2610,7 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
|
|
|
|
attribute_set_sockets.append(info.lf_attribute_set_socket);
|
|
|
|
|
used_sockets.append(lf_socket_usage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (lf::OutputSocket *joined_attribute_set = this->join_attribute_sets(
|
|
|
|
|
attribute_set_sockets, used_sockets, join_attribute_sets_cache)) {
|
|
|
|
|
lf_graph_->add_link(*joined_attribute_set, *lf_attribute_set_input);
|
|
|
|
|