Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2020-02-16 14:39:16 +0300
committerJacques Lucke <jacques@blender.org>2020-02-16 14:39:16 +0300
commitecc78d29d66d37dae73ab5fcabb6577ac021fd34 (patch)
treef84ddbef01122787699b7f2af4dfea68a223d5ed /source/blender/functions
parent4d74116218fc0c23920d2828f79e1d92803a40f1 (diff)
bring back more correct duplicate removal
Diffstat (limited to 'source/blender/functions')
-rw-r--r--source/blender/functions/FN_multi_function_network.h7
-rw-r--r--source/blender/functions/intern/multi_function_network.cc17
-rw-r--r--source/blender/functions/intern/multi_function_network_optimization.cc141
3 files changed, 150 insertions, 15 deletions
diff --git a/source/blender/functions/FN_multi_function_network.h b/source/blender/functions/FN_multi_function_network.h
index 5015cecb9cc..c6873cb9569 100644
--- a/source/blender/functions/FN_multi_function_network.h
+++ b/source/blender/functions/FN_multi_function_network.h
@@ -164,7 +164,7 @@ class MFNetworkBuilder : BLI::NonCopyable, BLI::NonMovable {
void remove_link(MFBuilderOutputSocket &from, MFBuilderInputSocket &to);
void remove_node(MFBuilderNode &node);
void remove_nodes(ArrayRef<MFBuilderNode *> nodes);
- void relink_origin(MFBuilderOutputSocket &new_from, MFBuilderInputSocket &to);
+ void replace_origin(MFBuilderOutputSocket &old_origin, MFBuilderOutputSocket &new_origin);
Array<bool> find_nodes_to_the_right_of__inclusive__mask(ArrayRef<MFBuilderNode *> nodes);
Array<bool> find_nodes_to_the_left_of__inclusive__mask(ArrayRef<MFBuilderNode *> nodes);
@@ -235,6 +235,11 @@ class MFNetworkBuilder : BLI::NonCopyable, BLI::NonMovable {
return this->socket_by_id(id).as_output();
}
+ ArrayRef<MFBuilderSocket *> sockets_or_null_by_id()
+ {
+ return m_socket_or_null_by_id;
+ }
+
ArrayRef<MFBuilderFunctionNode *> function_nodes() const
{
return m_function_nodes;
diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc
index ef22f435a66..883ff4f70d2 100644
--- a/source/blender/functions/intern/multi_function_network.cc
+++ b/source/blender/functions/intern/multi_function_network.cc
@@ -185,14 +185,17 @@ void MFNetworkBuilder::remove_link(MFBuilderOutputSocket &from, MFBuilderInputSo
to.m_origin = nullptr;
}
-void MFNetworkBuilder::relink_origin(MFBuilderOutputSocket &new_from, MFBuilderInputSocket &to)
+void MFNetworkBuilder::replace_origin(MFBuilderOutputSocket &old_origin,
+ MFBuilderOutputSocket &new_origin)
{
- BLI_assert(to.m_origin != nullptr);
- BLI_assert(to.m_origin != &new_from);
- BLI_assert(new_from.data_type() == to.data_type());
- to.m_origin->m_targets.remove_first_occurrence_and_reorder(&to);
- new_from.m_targets.append(&to);
- to.m_origin = &new_from;
+ BLI_assert(&old_origin != &new_origin);
+ BLI_assert(old_origin.data_type() == new_origin.data_type());
+ for (MFBuilderInputSocket *target : old_origin.targets()) {
+ BLI_assert(target->m_origin != nullptr);
+ target->m_origin = &new_origin;
+ new_origin.m_targets.append(target);
+ }
+ old_origin.m_targets.clear();
}
void MFNetworkBuilder::remove_node(MFBuilderNode &node)
diff --git a/source/blender/functions/intern/multi_function_network_optimization.cc b/source/blender/functions/intern/multi_function_network_optimization.cc
index c5d8fc319f7..6713a4146a0 100644
--- a/source/blender/functions/intern/multi_function_network_optimization.cc
+++ b/source/blender/functions/intern/multi_function_network_optimization.cc
@@ -12,8 +12,140 @@ namespace FN {
using BLI::MultiMap;
using BLI::Stack;
-void optimize_network__remove_duplicates(MFNetworkBuilder &UNUSED(network_builder))
+static uint32_t get_function_hash(const MultiFunction &fn)
{
+ return POINTER_AS_UINT(&fn);
+}
+
+static bool functions_are_equal(const MultiFunction &a, const MultiFunction &b)
+{
+ return &a == &b;
+}
+
+/* TODO: Use approriate caching to avoid doing the same checks many times. */
+static bool outputs_have_same_value(MFBuilderOutputSocket &a, MFBuilderOutputSocket &b)
+{
+ if (a.index() != b.index()) {
+ return false;
+ }
+ if (&a.node() == &b.node()) {
+ return true;
+ }
+ if (a.node().is_dummy() || b.node().is_dummy()) {
+ return false;
+ }
+ if (!functions_are_equal(a.node().as_function().function(), b.node().as_function().function())) {
+ return false;
+ }
+ for (uint i : a.node().inputs().index_range()) {
+ MFBuilderOutputSocket *origin_a = a.node().input(i).origin();
+ MFBuilderOutputSocket *origin_b = b.node().input(i).origin();
+ if (origin_a == nullptr || origin_b == nullptr) {
+ return false;
+ }
+ if (!outputs_have_same_value(*origin_a, *origin_b)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void optimize_network__remove_duplicates(MFNetworkBuilder &network_builder)
+{
+ Array<uint32_t> hash_by_output_socket(network_builder.socket_id_amount());
+ Array<bool> node_outputs_are_hashed(network_builder.node_id_amount(), false);
+
+ RNG *rng = BLI_rng_new(0);
+
+ for (MFBuilderDummyNode *node : network_builder.dummy_nodes()) {
+ for (MFBuilderOutputSocket *output_socket : node->outputs()) {
+ uint32_t output_hash = BLI_rng_get_uint(rng);
+ hash_by_output_socket[output_socket->id()] = output_hash;
+ }
+ node_outputs_are_hashed[node->id()] = true;
+ }
+
+ Stack<MFBuilderFunctionNode *> nodes_to_check = network_builder.function_nodes();
+ while (!nodes_to_check.is_empty()) {
+ MFBuilderFunctionNode &node = *nodes_to_check.peek();
+ if (node_outputs_are_hashed[node.id()]) {
+ nodes_to_check.pop();
+ continue;
+ }
+
+ bool all_dependencies_ready = true;
+ node.foreach_origin_node([&](MFBuilderNode &origin_node) {
+ if (!node_outputs_are_hashed[origin_node.id()]) {
+ all_dependencies_ready = false;
+ nodes_to_check.push(&origin_node.as_function());
+ }
+ });
+
+ if (!all_dependencies_ready) {
+ continue;
+ }
+
+ uint32_t combined_inputs_hash = BLI_RAND_PER_LINE_UINT32;
+ for (MFBuilderInputSocket *input_socket : node.inputs()) {
+ MFBuilderOutputSocket *origin = input_socket->origin();
+ uint32_t input_hash;
+ if (origin == nullptr) {
+ input_hash = BLI_rng_get_uint(rng);
+ }
+ else {
+ input_hash = hash_by_output_socket[origin->id()];
+ }
+ combined_inputs_hash = combined_inputs_hash * BLI_RAND_PER_LINE_UINT32 + input_hash;
+ }
+
+ uint32_t function_hash = get_function_hash(node.function());
+ uint32_t node_hash = combined_inputs_hash * BLI_RAND_PER_LINE_UINT32 + function_hash;
+
+ for (MFBuilderOutputSocket *output_socket : node.outputs()) {
+ uint32_t output_hash = node_hash *
+ (345741 + BLI_RAND_PER_LINE_UINT32 * output_socket->index());
+ hash_by_output_socket[output_socket->id()] = output_hash;
+ }
+
+ nodes_to_check.pop();
+ node_outputs_are_hashed[node.id()] = true;
+ }
+
+ MultiMap<uint32_t, MFBuilderOutputSocket *> outputs_by_hash;
+ for (uint id : hash_by_output_socket.index_range()) {
+ MFBuilderSocket *socket = network_builder.sockets_or_null_by_id()[id];
+ if (socket != nullptr && socket->is_output()) {
+ uint32_t output_hash = hash_by_output_socket[id];
+ outputs_by_hash.add(output_hash, &socket->as_output());
+ }
+ }
+
+ Vector<MFBuilderOutputSocket *> remaining_sockets;
+
+ outputs_by_hash.foreach_item(
+ [&](uint32_t UNUSED(hash), ArrayRef<MFBuilderOutputSocket *> outputs_with_hash) {
+ if (outputs_with_hash.size() <= 1) {
+ return;
+ }
+
+ remaining_sockets.clear();
+ ArrayRef<MFBuilderOutputSocket *> outputs_to_check = outputs_with_hash;
+ while (outputs_to_check.size() >= 2) {
+ MFBuilderOutputSocket &deduplicated_output = *outputs_to_check[0];
+ for (MFBuilderOutputSocket *socket : outputs_to_check.drop_front(1)) {
+ if (outputs_have_same_value(deduplicated_output, *socket)) {
+ network_builder.replace_origin(*socket, deduplicated_output);
+ }
+ else {
+ remaining_sockets.append(socket);
+ }
+ }
+
+ outputs_to_check = remaining_sockets;
+ }
+ });
+
+ BLI_rng_free(rng);
}
void optimize_network__remove_unused_nodes(MFNetworkBuilder &network_builder)
@@ -135,14 +267,9 @@ void optimize_network__constant_folding(MFNetworkBuilder &network_builder,
}
MFBuilderFunctionNode &folded_node = network_builder.add_function(*constant_fn);
-
MFBuilderOutputSocket &original_socket =
*dummy_nodes_to_compute[param_index]->input(0).origin();
-
- BLI::ScopedVector<MFBuilderInputSocket *> targets_copy = original_socket.targets();
- for (MFBuilderInputSocket *target : targets_copy) {
- network_builder.relink_origin(folded_node.output(0), *target);
- }
+ network_builder.replace_origin(original_socket, folded_node.output(0));
}
for (MFBuilderDummyNode *dummy_node : dummy_nodes_to_compute) {