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
This commit is contained in:
parent
136a06285f
commit
f517b3a295
Notes:
blender-bot
2023-02-14 06:57:56 +01:00
Referenced by issue #99932, Regression: Video in node group doesn't play Referenced by issue #98157, Regression: Massive drops in Animation playback (fps) in the viewport (Depsgraph)
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
/* 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 (can_have_gpu_material || BKE_image_user_id_has_animation(id)) {
|
||||
if (has_image_animation || BKE_image_user_id_has_animation(id)) {
|
||||
ID *id_cow = get_cow_id(id);
|
||||
add_operation_node(
|
||||
id,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue