[Bf-blender-cvs] [f517b3a2956] blender-v3.2-release: Fix T98157: improve animation fps with better check in depsgraph

Jacques Lucke noreply at git.blender.org
Wed May 18 16:43:34 CEST 2022


Commit: f517b3a29568fd43b722973c7c46d3c358ba0dda
Author: Jacques Lucke
Date:   Wed May 18 16:42:49 2022 +0200
Branches: blender-v3.2-release
https://developer.blender.org/rBf517b3a29568fd43b722973c7c46d3c358ba0dda

Fix T98157: improve animation fps with better check in depsgraph

Previously, the depsgraph assumed that every node tree might contain
a reference to a video. This resulted noticeable overhead when there
was no video.

Checking whether a node tree contained a video was relatively expensive
to do in the depsgraph. It is cheaper now due to the structure of the new
node tree updater.

This also adds an additional run-time field to `bNodeTree` (there are
quite a few already). We should move those to a separate run-time
struct, but not as part of a bug fix.

Differential Revision: https://developer.blender.org/D14957

===================================================================

M	source/blender/blenkernel/intern/node.cc
M	source/blender/blenkernel/intern/node_tree_update.cc
M	source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
M	source/blender/depsgraph/intern/builder/deg_builder_relations.cc
M	source/blender/makesdna/DNA_node_types.h

===================================================================

diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 200eefb73ec..e9c8b438284 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -670,6 +670,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
 
   ntree->progress = nullptr;
   ntree->execdata = nullptr;
+  ntree->runtime_flag = 0;
 
   ntree->field_inferencing_interface = nullptr;
   BKE_ntree_update_tag_missing_runtime_data(ntree);
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index baf3a0c8d22..8afe7ce7520 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -12,6 +12,7 @@
 #include "DNA_node_types.h"
 
 #include "BKE_anim_data.h"
+#include "BKE_image.h"
 #include "BKE_main.h"
 #include "BKE_node.h"
 #include "BKE_node_tree_update.h"
@@ -984,6 +985,7 @@ class NodeTreeMainUpdater {
     this->remove_unused_previews_when_necessary(ntree);
 
     this->ensure_tree_ref(ntree, tree_ref);
+    this->update_has_image_animation(*tree_ref);
     if (ntree.type == NTREE_GEOMETRY) {
       if (node_field_inferencing::update_field_inferencing(*tree_ref)) {
         result.interface_changed = true;
@@ -1254,6 +1256,35 @@ class NodeTreeMainUpdater {
     BKE_node_preview_remove_unused(&ntree);
   }
 
+  void update_has_image_animation(const NodeTreeRef &tree_ref)
+  {
+    bNodeTree &ntree = *tree_ref.btree();
+    ntree.runtime_flag &= ~NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
+    if (ntree.type != NTREE_SHADER) {
+      return;
+    }
+
+    /* Check if a used node group has an animated image. */
+    for (const NodeRef *group_node : tree_ref.nodes_by_type("NodeGroup")) {
+      const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id);
+      if (group != nullptr) {
+        if (group->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+          ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
+          return;
+        }
+      }
+    }
+    /* Check if the tree itself has an animated image. */
+    for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"})
+      for (const NodeRef *node : tree_ref.nodes_by_type(idname)) {
+        Image *image = reinterpret_cast<Image *>(node->bnode()->id);
+        if (image != nullptr && BKE_image_is_animated(image)) {
+          ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
+          return;
+        }
+      }
+  }
+
   void update_node_levels(bNodeTree &ntree)
   {
     ntreeUpdateNodeLevels(&ntree);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 4782f1c4a5d..c6fc3cd5d0b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -1078,14 +1078,17 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
 
 void DepsgraphNodeBuilder::build_animation_images(ID *id)
 {
-  /* GPU materials might use an animated image. However, these materials have no been built yet. We
-   * could scan the entire node tree recursively to check if any texture node has a video. That is
-   * quite expensive. For now just always add this operation node, because it is very fast. */
-  /* TODO: Add a more precise check when it is cheaper to iterate over all image nodes in a node
-   * tree. */
-  const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
-
-  if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) {
+  /* GPU materials might use an animated image. However, these materials have no been built yet so
+   * we have to check if they might be created during evaluation. */
+  bool has_image_animation = false;
+  if (ELEM(GS(id->name), ID_MA, ID_WO)) {
+    bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
+    if (ntree != nullptr && ntree->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+      has_image_animation = true;
+    }
+  }
+
+  if (has_image_animation || BKE_image_user_id_has_animation(id)) {
     ID *id_cow = get_cow_id(id);
     add_operation_node(
         id,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 5eccb5a4eb2..3eeab23823c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1446,10 +1446,15 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
 void DepsgraphRelationBuilder::build_animation_images(ID *id)
 {
   /* See #DepsgraphNodeBuilder::build_animation_images. */
-  const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+  bool has_image_animation = false;
+  if (ELEM(GS(id->name), ID_MA, ID_WO)) {
+    bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
+    if (ntree != nullptr && ntree->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+      has_image_animation = true;
+    }
+  }
 
-  /* TODO: can we check for existence of node for performance? */
-  if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) {
+  if (has_image_animation || BKE_image_user_id_has_animation(id)) {
     OperationKey image_animation_key(
         id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION);
     TimeSourceKey time_src_key;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index d18fe1b81dd..b66fe31c00e 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -499,7 +499,13 @@ typedef struct bNodeTree {
 
   int type;
 
-  char _pad1[4];
+  /**
+   * Used to cache run-time information of the node tree.
+   * #eNodeTreeRuntimeFlag.
+   */
+  uint8_t runtime_flag;
+
+  char _pad1[3];
 
   /**
    * Sockets in groups have unique identifiers, adding new sockets always
@@ -601,6 +607,11 @@ typedef enum eNodeTreeExecutionMode {
   NTREE_EXECUTION_MODE_FULL_FRAME = 1,
 } eNodeTreeExecutionMode;
 
+typedef enum eNodeTreeRuntimeFlag {
+  /** There is a node that references an image with animation. */
+  NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION = 1 << 0,
+} eNodeTreeRuntimeFlag;
+
 /* socket value structs for input buttons
  * DEPRECATED now using ID properties
  */



More information about the Bf-blender-cvs mailing list