Node Editor: Use the topology cache more when drawing node tree

Partly a cleanup, but also iterating over spans can be faster than
linked lists. Also rewrite the multi-input socket link counting
to avoid the need for a temporary map. Overall, on my setup the changes
save about 5% (3ms) when drawing a large node tree (the mouse house file).
This commit is contained in:
Hans Goudey 2023-01-02 17:55:32 -05:00
parent e550d8c8fd
commit 0c30873d82
2 changed files with 32 additions and 42 deletions

View File

@ -169,7 +169,10 @@ class bNodeSocketRuntime : NonCopyable, NonMovable {
float locx = 0;
float locy = 0;
/* Runtime-only cache of the number of input links, for multi-input sockets. */
/**
* Runtime-only cache of the number of input links, for multi-input sockets,
* including dragged node links that aren't actually in the tree.
*/
short total_inputs = 0;
/** Only valid when #topology_cache_is_dirty is false. */

View File

@ -348,7 +348,7 @@ static void node_update_basis(const bContext &C,
bool add_output_space = false;
int buty;
LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
for (bNodeSocket *socket : node.output_sockets()) {
if (!socket->is_visible()) {
continue;
}
@ -471,7 +471,7 @@ static void node_update_basis(const bContext &C,
}
/* Input sockets. */
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
for (bNodeSocket *socket : node.input_sockets()) {
if (!socket->is_visible()) {
continue;
}
@ -564,12 +564,12 @@ static void node_update_hidden(bNode &node, uiBlock &block)
loc.y = round(loc.y);
/* Calculate minimal radius. */
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
for (const bNodeSocket *socket : node.input_sockets()) {
if (socket->is_visible()) {
totin++;
}
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
for (const bNodeSocket *socket : node.output_sockets()) {
if (socket->is_visible()) {
totout++;
}
@ -590,7 +590,7 @@ static void node_update_hidden(bNode &node, uiBlock &block)
float rad = float(M_PI) / (1.0f + float(totout));
float drad = rad;
LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
for (bNodeSocket *socket : node.output_sockets()) {
if (socket->is_visible()) {
/* Round the socket location to stop it from jiggling. */
socket->runtime->locx = round(node.runtime->totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
@ -602,7 +602,7 @@ static void node_update_hidden(bNode &node, uiBlock &block)
/* Input sockets. */
rad = drad = -float(M_PI) / (1.0f + float(totin));
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
for (bNodeSocket *socket : node.input_sockets()) {
if (socket->is_visible()) {
/* Round the socket location to stop it from jiggling. */
socket->runtime->locx = round(node.runtime->totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
@ -1397,10 +1397,7 @@ static void node_draw_sockets(const View2D &v2d,
const bool draw_outputs,
const bool select_all)
{
const uint total_input_len = BLI_listbase_count(&node.inputs);
const uint total_output_len = BLI_listbase_count(&node.outputs);
if (total_input_len + total_output_len == 0) {
if (node.input_sockets().is_empty() && node.output_sockets().is_empty()) {
return;
}
@ -1431,12 +1428,12 @@ static void node_draw_sockets(const View2D &v2d,
scale *= socket_draw_size;
if (!select_all) {
immBeginAtMost(GPU_PRIM_POINTS, total_input_len + total_output_len);
immBeginAtMost(GPU_PRIM_POINTS, node.input_sockets().size() + node.output_sockets().size());
}
/* Socket inputs. */
short selected_input_len = 0;
LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
int selected_input_len = 0;
for (const bNodeSocket *sock : node.input_sockets()) {
if (!sock->is_visible()) {
continue;
}
@ -1467,9 +1464,9 @@ static void node_draw_sockets(const View2D &v2d,
}
/* Socket outputs. */
short selected_output_len = 0;
int selected_output_len = 0;
if (draw_outputs) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
for (const bNodeSocket *sock : node.output_sockets()) {
if (!sock->is_visible()) {
continue;
}
@ -1507,7 +1504,7 @@ static void node_draw_sockets(const View2D &v2d,
if (selected_input_len) {
/* Socket inputs. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
for (const bNodeSocket *sock : node.input_sockets()) {
if (!sock->is_visible()) {
continue;
}
@ -1537,7 +1534,7 @@ static void node_draw_sockets(const View2D &v2d,
if (selected_output_len) {
/* Socket outputs. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
for (const bNodeSocket *sock : node.output_sockets()) {
if (!sock->is_visible()) {
continue;
}
@ -1571,7 +1568,7 @@ static void node_draw_sockets(const View2D &v2d,
/* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox`
* rather than with `GL_POINT`. */
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
for (const bNodeSocket *socket : node.input_sockets()) {
if (!socket->is_visible()) {
continue;
}
@ -1905,7 +1902,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(
GEO_NODE_REMOVE_ATTRIBUTE,
GEO_NODE_INPUT_NAMED_ATTRIBUTE)) {
/* Only show the overlay when the name is passed in from somewhere else. */
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
for (const bNodeSocket *socket : node.input_sockets()) {
if (STREQ(socket->name, "Name")) {
if (!socket->is_directly_linked()) {
return std::nullopt;
@ -2037,7 +2034,6 @@ static void node_draw_extra_info_panel(TreeDrawContext &tree_draw_ctx,
uiBlock &block)
{
Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(tree_draw_ctx, snode, node);
if (extra_info_rows.size() == 0) {
return;
}
@ -2048,7 +2044,7 @@ static void node_draw_extra_info_panel(TreeDrawContext &tree_draw_ctx,
const float width = (node.width - 6.0f) * U.dpi_fac;
if (node.type == NODE_FRAME) {
if (node.is_frame()) {
extra_info_rect.xmin = rct.xmin;
extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
extra_info_rect.ymin = rct.ymin + 2.0f * U.dpi_fac;
@ -2655,27 +2651,18 @@ void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
static void count_multi_input_socket_links(bNodeTree &ntree, SpaceNode &snode)
{
Map<bNodeSocket *, int> counts;
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
int &count = counts.lookup_or_add(link->tosock, 0);
count++;
for (bNode *node : ntree.all_nodes()) {
for (bNodeSocket *socket : node->input_sockets()) {
if (socket->is_multi_input()) {
socket->runtime->total_inputs = socket->directly_linked_links().size();
}
}
}
/* Count temporary links going into this socket. */
if (snode.runtime->linkdrag) {
for (const bNodeLink &link : snode.runtime->linkdrag->links) {
if (link.tosock && (link.tosock->flag & SOCK_MULTI_INPUT)) {
int &count = counts.lookup_or_add(link.tosock, 0);
count++;
}
}
}
for (bNode *node : ntree.all_nodes()) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->flag & SOCK_MULTI_INPUT) {
socket->runtime->total_inputs = counts.lookup_default(socket, 0);
link.tosock->runtime->total_inputs++;
}
}
}
@ -2768,12 +2755,12 @@ static void node_update_nodetree(const bContext &C,
for (const int i : nodes.index_range()) {
bNode &node = *nodes[i];
uiBlock &block = *blocks[i];
if (node.type == NODE_FRAME) {
if (node.is_frame()) {
/* Frame sizes are calculated after all other nodes have calculating their #totr. */
continue;
}
if (node.type == NODE_REROUTE) {
if (node.is_reroute()) {
reroute_node_prepare_for_draw(node);
}
else {
@ -2789,7 +2776,7 @@ static void node_update_nodetree(const bContext &C,
/* Now calculate the size of frame nodes, which can depend on the size of other nodes.
* Update nodes in reverse, so children sizes get updated before parents. */
for (int i = nodes.size() - 1; i >= 0; i--) {
if (nodes[i]->type == NODE_FRAME) {
if (nodes[i]->is_frame()) {
frame_node_prepare_for_draw(*nodes[i], nodes);
}
}
@ -2992,10 +2979,10 @@ static void node_draw(const bContext &C,
uiBlock &block,
bNodeInstanceKey key)
{
if (node.type == NODE_FRAME) {
if (node.is_frame()) {
frame_node_draw(C, tree_draw_ctx, region, snode, ntree, node, block);
}
else if (node.type == NODE_REROUTE) {
else if (node.is_reroute()) {
reroute_node_draw(C, region, ntree, node, block);
}
else {