From 5be95161a49ffed4ef82c09ebe8d5fb42dec4a48 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 14 Oct 2025 12:06:56 +0200 Subject: [PATCH] Fix #147747: Shader Nodes: wrong code gen order Currently, sometimes shader code generation fails because the code of top-level nodes is interleaved with the code of a repeat zone. See #147747 for more details. Previously, the code-generation order was just the standard toposort of the node tree, but it does not guarantee that all nodes in a zone are next to each other. Also, it can't easily, because the zone detection itself depends on the toposort. This patch implements another sorting step on top of the default toposort. It packs nodes in zones together without changing the validity of the toposort. This is an alternative to #147999. Pull Request: https://projects.blender.org/blender/blender/pulls/148005 --- source/blender/nodes/intern/node_exec.cc | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc index bfd630b0fde..7c20fc13b5a 100644 --- a/source/blender/nodes/intern/node_exec.cc +++ b/source/blender/nodes/intern/node_exec.cc @@ -14,6 +14,7 @@ #include "BKE_global.hh" #include "BKE_node_runtime.hh" #include "BKE_node_tree_update.hh" +#include "BKE_node_tree_zones.hh" #include "MEM_guardedalloc.h" @@ -142,6 +143,43 @@ static bNodeStack *setup_stack(bNodeStack *stack, bNodeTree *ntree, bNode *node, return ns; } +static blender::Vector get_node_code_gen_order(bNodeTree &ntree) +{ + using namespace blender; + ntree.ensure_topology_cache(); + Vector nodes = ntree.toposort_left_to_right(); + const bke::bNodeTreeZones *zones = ntree.zones(); + if (!zones) { + return nodes; + } + /* Insertion sort to make sure that all nodes in a zone are packed together right before the zone + * output. */ + for (int old_i = nodes.size() - 1; old_i >= 0; old_i--) { + bNode *node = nodes[old_i]; + const bke::bNodeTreeZone *zone = zones->get_zone_by_node(node->identifier); + if (!zone) { + /* Nones outside of any zone can stay where they are. */ + continue; + } + if (zone->output_node_id == node->identifier) { + /* The output of a zone should not be moved. */ + continue; + } + for (int new_i = old_i + 1; new_i < nodes.size(); new_i++) { + bNode *next_node = nodes[new_i]; + const bke::bNodeTreeZone *zone_to_check = zones->get_zone_by_node(next_node->identifier); + if (zone_to_check && + (zone == zone_to_check || zone->contains_zone_recursively(*zone_to_check))) + { + /* Don't move the node further than the next node in the zone. */ + break; + } + std::swap(nodes[new_i - 1], nodes[new_i]); + } + } + return nodes; +} + bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNodeInstanceKey parent_key) @@ -162,7 +200,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, BKE_ntree_update_after_single_tree_change(*G.main, *ntree); ntree->ensure_topology_cache(); - const Span nodelist = ntree->toposort_left_to_right(); + Vector nodelist = get_node_code_gen_order(*ntree); /* XXX could let callbacks do this for specialized data */ exec = MEM_callocN("node tree execution data");