Fix T70325 EEVEE: Performance regression with large nodetrees
This was caused by nodeChainIter which is not linear complexity. Introduce nodeChainIterBackwards to iterate backwards faster.
This commit is contained in:
@@ -591,6 +591,10 @@ void nodeChainIter(const bNodeTree *ntree,
|
|||||||
bool (*callback)(bNode *, bNode *, void *, const bool),
|
bool (*callback)(bNode *, bNode *, void *, const bool),
|
||||||
void *userdata,
|
void *userdata,
|
||||||
const bool reversed);
|
const bool reversed);
|
||||||
|
void nodeChainIterBackwards(const bNodeTree *ntree,
|
||||||
|
const bNode *node_start,
|
||||||
|
bool (*callback)(bNode *, bNode *, void *),
|
||||||
|
void *userdata);
|
||||||
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
|
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
|
||||||
|
|
||||||
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
|
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
|
||||||
|
@@ -947,6 +947,57 @@ void nodeChainIter(const bNodeTree *ntree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iter_backwards_ex(const bNodeTree *ntree,
|
||||||
|
const bNode *node_start,
|
||||||
|
bool (*callback)(bNode *, bNode *, void *),
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) {
|
||||||
|
bNodeLink *link = sock->link;
|
||||||
|
if (link == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((link->flag & NODE_LINK_VALID) == 0) {
|
||||||
|
/* Skip links marked as cyclic. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (link->fromnode->iter_flag) {
|
||||||
|
/* Only iter on nodes once. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
link->fromnode->iter_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!callback(link->fromnode, link->tonode, userdata)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iter_backwards_ex(ntree, link->fromnode, callback, userdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over a chain of nodes, starting with \a node_start, executing
|
||||||
|
* \a callback for each node (which can return false to end iterator).
|
||||||
|
*
|
||||||
|
* Faster than nodeChainIter. Iter only once per node.
|
||||||
|
*
|
||||||
|
* \note Needs updated socket links (ntreeUpdateTree).
|
||||||
|
* \note Recursive
|
||||||
|
*/
|
||||||
|
void nodeChainIterBackwards(const bNodeTree *ntree,
|
||||||
|
const bNode *node_start,
|
||||||
|
bool (*callback)(bNode *, bNode *, void *),
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
/* Reset flag. */
|
||||||
|
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||||
|
node->iter_flag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter_backwards_ex(ntree, node_start, callback, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over all parents of \a node, executing \a callback for each parent
|
* Iterate over all parents of \a node, executing \a callback for each parent
|
||||||
* (which can return false to end iterator)
|
* (which can return false to end iterator)
|
||||||
|
@@ -277,7 +277,9 @@ typedef struct bNode {
|
|||||||
/** Used at runtime when going through the tree. Initialize before use. */
|
/** Used at runtime when going through the tree. Initialize before use. */
|
||||||
short tmp_flag;
|
short tmp_flag;
|
||||||
/** Used at runtime to tag derivatives branches. EEVEE only. */
|
/** Used at runtime to tag derivatives branches. EEVEE only. */
|
||||||
short branch_tag;
|
char branch_tag;
|
||||||
|
/** Used at runtime when iterating over node branches. */
|
||||||
|
char iter_flag;
|
||||||
/** Runtime during drawing. */
|
/** Runtime during drawing. */
|
||||||
struct uiBlock *block;
|
struct uiBlock *block;
|
||||||
|
|
||||||
|
@@ -597,10 +597,7 @@ static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
|
|||||||
ntreeUpdateTree(G.main, ntree);
|
ntreeUpdateTree(G.main, ntree);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ntree_branch_count_and_tag_nodes(bNode *fromnode,
|
static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
|
||||||
bNode *tonode,
|
|
||||||
void *userdata,
|
|
||||||
const bool UNUSED(reversed))
|
|
||||||
{
|
{
|
||||||
int *node_count = (int *)userdata;
|
int *node_count = (int *)userdata;
|
||||||
if (fromnode->tmp_flag == -1) {
|
if (fromnode->tmp_flag == -1) {
|
||||||
@@ -629,7 +626,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
|
|||||||
/* Count and tag all nodes inside the displacement branch of the tree. */
|
/* Count and tag all nodes inside the displacement branch of the tree. */
|
||||||
start_node->tmp_flag = 0;
|
start_node->tmp_flag = 0;
|
||||||
int node_count = 1;
|
int node_count = 1;
|
||||||
nodeChainIter(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, true);
|
nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count);
|
||||||
/* Make a full copy of the branch */
|
/* Make a full copy of the branch */
|
||||||
bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
|
bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
|
||||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||||
@@ -763,10 +760,7 @@ static void node_tag_branch_as_derivative(bNode *node, int dx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode),
|
static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode), bNode *tonode, void *userdata)
|
||||||
bNode *tonode,
|
|
||||||
void *userdata,
|
|
||||||
const bool UNUSED(reversed))
|
|
||||||
{
|
{
|
||||||
bNodeTree *ntree = (bNodeTree *)userdata;
|
bNodeTree *ntree = (bNodeTree *)userdata;
|
||||||
|
|
||||||
@@ -794,17 +788,8 @@ static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode),
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ntree_tag_bsdf_cb(bNode *fromnode,
|
static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata)
|
||||||
bNode *UNUSED(tonode),
|
|
||||||
void *userdata,
|
|
||||||
const bool UNUSED(reversed))
|
|
||||||
{
|
{
|
||||||
/* Don't evaluate nodes more than once. */
|
|
||||||
if (fromnode->tmp_flag) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
fromnode->tmp_flag = 1;
|
|
||||||
|
|
||||||
switch (fromnode->type) {
|
switch (fromnode->type) {
|
||||||
case SH_NODE_BSDF_ANISOTROPIC:
|
case SH_NODE_BSDF_ANISOTROPIC:
|
||||||
case SH_NODE_EEVEE_SPECULAR:
|
case SH_NODE_EEVEE_SPECULAR:
|
||||||
@@ -844,12 +829,7 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag
|
|||||||
/* Make sure sockets links pointers are correct. */
|
/* Make sure sockets links pointers are correct. */
|
||||||
ntreeUpdateTree(G.main, ntree);
|
ntreeUpdateTree(G.main, ntree);
|
||||||
|
|
||||||
/* Reset visit flag. */
|
nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags);
|
||||||
for (bNode *node = ntree->nodes.first; node; node = node->next) {
|
|
||||||
node->tmp_flag = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeChainIter(ntree, output_node, ntree_tag_bsdf_cb, tags, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This one needs to work on a local tree. */
|
/* This one needs to work on a local tree. */
|
||||||
@@ -878,7 +858,7 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
|
|||||||
|
|
||||||
/* Duplicate bump height branches for manual derivatives.
|
/* Duplicate bump height branches for manual derivatives.
|
||||||
*/
|
*/
|
||||||
nodeChainIter(localtree, output, ntree_shader_bump_branches, localtree, true);
|
nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree);
|
||||||
|
|
||||||
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
|
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
|
||||||
nTreeTags tags = {
|
nTreeTags tags = {
|
||||||
|
Reference in New Issue
Block a user