Merge branch 'blender-v4.0-release'

This commit is contained in:
Jacques Lucke
2023-10-20 21:22:11 +02:00
2 changed files with 165 additions and 64 deletions

View File

@@ -8,12 +8,14 @@
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_anonymous_attributes.hh"
#include "BKE_node_tree_dot_export.hh"
#include "BKE_node_tree_zones.hh"
#include "BLI_bit_group_vector.hh"
#include "BLI_bit_span_ops.hh"
#include "BLI_resource_scope.hh"
#include <iostream>
#include <sstream>
namespace blender::bke::anonymous_attribute_inferencing {
@@ -195,6 +197,21 @@ class bNodeTreeToDotOptionsForAnonymousAttributeInferencing : public bNodeTreeTo
}
};
static bool or_into_each_other(MutableBoundedBitSpan a, MutableBoundedBitSpan b)
{
if (bits::spans_equal(a, b)) {
return false;
}
a |= b;
b |= a;
return true;
}
static bool or_into_each_other(BitGroupVector<> &vec, const int64_t a, const int64_t b)
{
return or_into_each_other(vec[a], vec[b]);
}
static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
const bNodeTree &tree)
{
@@ -204,6 +221,22 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
ResourceScope scope;
const Array<const aal::RelationsInNode *> relations_by_node = get_relations_by_node(tree, scope);
/* Repeat zones need some special behavior because they can propagate anonymous attributes from
* right to left (from the repeat output to the repeat input node). */
const bNodeTreeZones *zones = tree.zones();
Vector<const bNodeTreeZone *> repeat_zones_to_consider;
if (zones) {
for (const std::unique_ptr<bNodeTreeZone> &zone : zones->zones) {
if (ELEM(nullptr, zone->input_node, zone->output_node)) {
continue;
}
if (zone->output_node->type != GEO_NODE_REPEAT_OUTPUT) {
continue;
}
repeat_zones_to_consider.append(zone.get());
}
}
Vector<FieldSource> all_field_sources;
Vector<GeometrySource> all_geometry_sources;
@@ -300,44 +333,72 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
/* Inferencing pass from left to right to figure out where fields and geometries may be
* propagated to. */
for (const bNode *node : tree.toposort_left_to_right()) {
for (const bNodeSocket *socket : node->input_sockets()) {
if (!socket->is_available()) {
continue;
}
const int dst_index = socket->index_in_tree();
for (const bNodeLink *link : socket->directly_linked_links()) {
if (link->is_used()) {
const int src_index = link->fromsock->index_in_tree();
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
propagated_geometries_by_socket[dst_index] |= propagated_geometries_by_socket[src_index];
available_fields_by_geometry_socket[dst_index] |=
available_fields_by_geometry_socket[src_index];
auto pass_left_to_right = [&]() {
for (const bNode *node : tree.toposort_left_to_right()) {
for (const bNodeSocket *socket : node->input_sockets()) {
if (!socket->is_available()) {
continue;
}
const int dst_index = socket->index_in_tree();
for (const bNodeLink *link : socket->directly_linked_links()) {
if (link->is_used()) {
const int src_index = link->fromsock->index_in_tree();
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
propagated_geometries_by_socket[dst_index] |=
propagated_geometries_by_socket[src_index];
available_fields_by_geometry_socket[dst_index] |=
available_fields_by_geometry_socket[src_index];
}
}
}
}
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
for (const aal::ReferenceRelation &relation : relations.reference_relations) {
const bNodeSocket &from_socket = node->input_socket(relation.from_field_input);
const bNodeSocket &to_socket = node->output_socket(relation.to_field_output);
if (!from_socket.is_available() || !to_socket.is_available()) {
continue;
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
for (const aal::ReferenceRelation &relation : relations.reference_relations) {
const bNodeSocket &from_socket = node->input_socket(relation.from_field_input);
const bNodeSocket &to_socket = node->output_socket(relation.to_field_output);
if (!from_socket.is_available() || !to_socket.is_available()) {
continue;
}
const int src_index = from_socket.index_in_tree();
const int dst_index = to_socket.index_in_tree();
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
}
const int src_index = from_socket.index_in_tree();
const int dst_index = to_socket.index_in_tree();
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
}
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
const bNodeSocket &from_socket = node->input_socket(relation.from_geometry_input);
const bNodeSocket &to_socket = node->output_socket(relation.to_geometry_output);
if (!from_socket.is_available() || !to_socket.is_available()) {
continue;
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
const bNodeSocket &from_socket = node->input_socket(relation.from_geometry_input);
const bNodeSocket &to_socket = node->output_socket(relation.to_geometry_output);
if (!from_socket.is_available() || !to_socket.is_available()) {
continue;
}
const int src_index = from_socket.index_in_tree();
const int dst_index = to_socket.index_in_tree();
propagated_geometries_by_socket[dst_index] |= propagated_geometries_by_socket[src_index];
available_fields_by_geometry_socket[dst_index] |=
available_fields_by_geometry_socket[src_index];
}
const int src_index = from_socket.index_in_tree();
const int dst_index = to_socket.index_in_tree();
propagated_geometries_by_socket[dst_index] |= propagated_geometries_by_socket[src_index];
available_fields_by_geometry_socket[dst_index] |=
available_fields_by_geometry_socket[src_index];
}
};
while (true) {
pass_left_to_right();
/* Repeat zones may need multiple inference passes. That's because anonymous attributes
* propagated to a repeat output node also come out of the corresponding repeat input node. */
bool changed = false;
for (const bNodeTreeZone *zone : repeat_zones_to_consider) {
const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(
zone->output_node->storage);
for (const int i : IndexRange(storage.items_num)) {
const bNodeSocket &body_input_socket = zone->input_node->output_socket(i);
const bNodeSocket &body_output_socket = zone->output_node->input_socket(i);
const int in_index = body_input_socket.index_in_tree();
const int out_index = body_output_socket.index_in_tree();
changed |= or_into_each_other(propagated_fields_by_socket, in_index, out_index);
changed |= or_into_each_other(propagated_geometries_by_socket, in_index, out_index);
changed |= or_into_each_other(available_fields_by_geometry_socket, in_index, out_index);
}
}
if (!changed) {
break;
}
}
@@ -346,8 +407,8 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
VectorSet<int> propagated_output_geometry_indices;
aal::RelationsInNode tree_relations;
/* Create #PropagateRelation, #AvailableRelation and #ReferenceRelation for the tree based on the
* propagated data from above. */
/* Create #PropagateRelation, #AvailableRelation and #ReferenceRelation for the tree based on
* the propagated data from above. */
if (const bNode *group_output_node = tree.group_output_node()) {
for (const bNodeSocket *socket : group_output_node->input_sockets().drop_back(1)) {
if (socket->type == SOCK_GEOMETRY) {
@@ -410,38 +471,64 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
/* Inferencing pass from right to left to determine which anonymous attributes have to be
* propagated to which geometry sockets. */
for (const bNode *node : tree.toposort_right_to_left()) {
for (const bNodeSocket *socket : node->output_sockets()) {
if (!socket->is_available()) {
continue;
}
const int dst_index = socket->index_in_tree();
for (const bNodeLink *link : socket->directly_linked_links()) {
if (link->is_used()) {
const int src_index = link->tosock->index_in_tree();
required_fields_by_geometry_socket[dst_index] |=
required_fields_by_geometry_socket[src_index];
propagate_to_output_by_geometry_socket[dst_index] |=
propagate_to_output_by_geometry_socket[src_index];
auto pass_right_to_left = [&]() {
for (const bNode *node : tree.toposort_right_to_left()) {
for (const bNodeSocket *socket : node->output_sockets()) {
if (!socket->is_available()) {
continue;
}
const int dst_index = socket->index_in_tree();
for (const bNodeLink *link : socket->directly_linked_links()) {
if (link->is_used()) {
const int src_index = link->tosock->index_in_tree();
required_fields_by_geometry_socket[dst_index] |=
required_fields_by_geometry_socket[src_index];
propagate_to_output_by_geometry_socket[dst_index] |=
propagate_to_output_by_geometry_socket[src_index];
}
}
}
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
const bNodeSocket &output_socket = node->output_socket(relation.to_geometry_output);
const bNodeSocket &input_socket = node->input_socket(relation.from_geometry_input);
const int src_index = output_socket.index_in_tree();
const int dst_index = input_socket.index_in_tree();
required_fields_by_geometry_socket[dst_index] |=
required_fields_by_geometry_socket[src_index];
propagate_to_output_by_geometry_socket[dst_index] |=
propagate_to_output_by_geometry_socket[src_index];
}
for (const aal::EvalRelation &relation : relations.eval_relations) {
const bNodeSocket &geometry_socket = node->input_socket(relation.geometry_input);
const bNodeSocket &field_socket = node->input_socket(relation.field_input);
required_fields_by_geometry_socket[geometry_socket.index_in_tree()] |=
propagated_fields_by_socket[field_socket.index_in_tree()];
}
}
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
const bNodeSocket &output_socket = node->output_socket(relation.to_geometry_output);
const bNodeSocket &input_socket = node->input_socket(relation.from_geometry_input);
const int src_index = output_socket.index_in_tree();
const int dst_index = input_socket.index_in_tree();
required_fields_by_geometry_socket[dst_index] |=
required_fields_by_geometry_socket[src_index];
propagate_to_output_by_geometry_socket[dst_index] |=
propagate_to_output_by_geometry_socket[src_index];
};
while (true) {
pass_right_to_left();
/* Data required by a repeat input node will also be required by the repeat output node,
* because that's where the data comes from after the first iteration. */
bool changed = false;
for (const bNodeTreeZone *zone : repeat_zones_to_consider) {
const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(
zone->output_node->storage);
for (const int i : IndexRange(storage.items_num)) {
const bNodeSocket &body_input_socket = zone->input_node->output_socket(i);
const bNodeSocket &body_output_socket = zone->output_node->input_socket(i);
const int in_index = body_input_socket.index_in_tree();
const int out_index = body_output_socket.index_in_tree();
changed |= or_into_each_other(required_fields_by_geometry_socket, in_index, out_index);
changed |= or_into_each_other(propagate_to_output_by_geometry_socket, in_index, out_index);
}
}
for (const aal::EvalRelation &relation : relations.eval_relations) {
const bNodeSocket &geometry_socket = node->input_socket(relation.geometry_input);
const bNodeSocket &field_socket = node->input_socket(relation.field_input);
required_fields_by_geometry_socket[geometry_socket.index_in_tree()] |=
propagated_fields_by_socket[field_socket.index_in_tree()];
if (!changed) {
break;
}
}

View File

@@ -238,9 +238,23 @@ template<typename... BitSpanT> inline bool has_common_set_bits(const BitSpanT &.
return any_set_expr([](const auto... x) { return (x & ...); }, args...);
}
template<typename BitSpanT> inline bool any_bit_set(const BitSpanT &arg)
{
return has_common_set_bits(arg);
}
template<typename BitSpanT, typename Fn> inline void foreach_1_index(const BitSpanT &data, Fn &&fn)
{
foreach_1_index_expr([](const BitInt x) { return x; }, fn, data);
}
template<typename BitSpanT1, typename BitSpanT2>
inline bool spans_equal(const BitSpanT1 &a, const BitSpanT2 &b)
{
if (a.size() != b.size()) {
return false;
}
return !any_set_expr([](const BitInt a, const BitInt b) { return a ^ b; }, a, b);
}
} // namespace blender::bits