Depsgraph: Add generic animated properties cache

Allows to speed up lookups like "is property FOO of data BAR animated".
Can be used to optimize object's visibility check, but also allows to
check animation on bones without too much of time penalty.

The cache is shared between both nodes and relations builder.

Currently is not used, just a boilerplate for an upcoming changes in
an actual logic.
This commit is contained in:
Sergey Sharybin 2019-04-29 12:55:29 +02:00
parent 587ee46d88
commit c8f3377d03
Notes: blender-bot 2023-06-21 19:23:24 +02:00
Referenced by issue #77124, [WIP] Cache `RNA_path_resolve` in dependency graph
12 changed files with 324 additions and 16 deletions

View File

@ -37,6 +37,7 @@ set(INC_SYS
set(SRC
intern/builder/deg_builder.cc
intern/builder/deg_builder_cache.cc
intern/builder/deg_builder_cycle.cc
intern/builder/deg_builder_map.cc
intern/builder/deg_builder_nodes.cc
@ -82,6 +83,7 @@ set(SRC
DEG_depsgraph_query.h
intern/builder/deg_builder.h
intern/builder/deg_builder_cache.h
intern/builder/deg_builder_cycle.h
intern/builder/deg_builder_map.h
intern/builder/deg_builder_nodes.h

View File

@ -55,6 +55,11 @@ namespace DEG {
* Base class for builders.
*/
DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache)
: bmain_(bmain), graph_(graph), cache_(cache)
{
}
namespace {
struct VisibilityCheckData {
@ -108,10 +113,6 @@ bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base)
return false;
}
DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph) : bmain_(bmain), graph_(graph)
{
}
bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
{
return deg_check_base_available_for_build(graph_, base);

View File

@ -29,17 +29,20 @@ struct Main;
namespace DEG {
struct Depsgraph;
class DepsgraphBuilderCache;
class DepsgraphBuilder {
public:
bool need_pull_base_into_graph(struct Base *base);
protected:
DepsgraphBuilder(Main *bmain, Depsgraph *graph);
/* NOTE: The builder does NOT take ownership over any of those resources. */
DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache);
/* State which never changes, same for the whole builder time. */
Main *bmain_;
Depsgraph *graph_;
DepsgraphBuilderCache *cache_;
};
bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base);

View File

@ -0,0 +1,186 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2018 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup depsgraph
*/
#include "intern/builder/deg_builder_cache.h"
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "BLI_utildefines.h"
extern "C" {
#include "BKE_animsys.h"
}
namespace DEG {
/* Animated property storage. */
AnimatedPropertyID::AnimatedPropertyID() : data(NULL), property_rna(NULL)
{
}
AnimatedPropertyID::AnimatedPropertyID(const PointerRNA *pointer_rna,
const PropertyRNA *property_rna)
: AnimatedPropertyID(*pointer_rna, property_rna)
{
}
AnimatedPropertyID::AnimatedPropertyID(const PointerRNA &pointer_rna,
const PropertyRNA *property_rna)
: data(pointer_rna.data), property_rna(property_rna)
{
}
AnimatedPropertyID::AnimatedPropertyID(ID *id, StructRNA *type, const char *property_name)
: data(id)
{
property_rna = RNA_struct_type_find_property(type, property_name);
}
AnimatedPropertyID::AnimatedPropertyID(ID * /*id*/,
StructRNA *type,
void *data,
const char *property_name)
: data(data)
{
property_rna = RNA_struct_type_find_property(type, property_name);
}
bool AnimatedPropertyID::operator<(const AnimatedPropertyID &other) const
{
if (data < other.data) {
return true;
}
else if (data == other.data) {
return property_rna < other.property_rna;
}
return false;
}
namespace {
struct AnimatedPropertyCallbackData {
PointerRNA pointer_rna;
AnimatedPropertyStorage *animated_property_storage;
DepsgraphBuilderCache *builder_cache;
};
void animated_property_cb(ID * /*id*/, FCurve *fcurve, void *data_v)
{
if (fcurve->rna_path == NULL || fcurve->rna_path[0] == '\0') {
return;
}
AnimatedPropertyCallbackData *data = static_cast<AnimatedPropertyCallbackData *>(data_v);
/* Resolve property. */
PointerRNA pointer_rna;
PropertyRNA *property_rna = NULL;
if (!RNA_path_resolve_property(
&data->pointer_rna, fcurve->rna_path, &pointer_rna, &property_rna)) {
return;
}
/* Get storage for the ID.
* This is needed to deal with cases when nested datablock is animated by its parent. */
AnimatedPropertyStorage *animated_property_storage = data->animated_property_storage;
if (pointer_rna.id.data != data->pointer_rna.id.data) {
animated_property_storage = data->builder_cache->ensureAnimatedPropertyStorage(
reinterpret_cast<ID *>(pointer_rna.id.data));
}
/* Set the property as animated. */
animated_property_storage->tagPropertyAsAnimated(&pointer_rna, property_rna);
}
} // namespace
AnimatedPropertyStorage::AnimatedPropertyStorage() : is_fully_initialized(false)
{
}
void AnimatedPropertyStorage::initializeFromID(DepsgraphBuilderCache *builder_cache, ID *id)
{
AnimatedPropertyCallbackData data;
RNA_id_pointer_create(id, &data.pointer_rna);
data.animated_property_storage = this;
data.builder_cache = builder_cache;
BKE_fcurves_id_cb(id, animated_property_cb, &data);
}
void AnimatedPropertyStorage::tagPropertyAsAnimated(const AnimatedPropertyID &property_id)
{
animated_properties_set.insert(property_id);
}
void AnimatedPropertyStorage::tagPropertyAsAnimated(const PointerRNA *pointer_rna,
const PropertyRNA *property_rna)
{
tagPropertyAsAnimated(AnimatedPropertyID(pointer_rna, property_rna));
}
bool AnimatedPropertyStorage::isPropertyAnimated(const AnimatedPropertyID &property_id)
{
return animated_properties_set.find(property_id) != animated_properties_set.end();
}
bool AnimatedPropertyStorage::isPropertyAnimated(const PointerRNA *pointer_rna,
const PropertyRNA *property_rna)
{
return isPropertyAnimated(AnimatedPropertyID(pointer_rna, property_rna));
}
/* Builder cache itself. */
DepsgraphBuilderCache::DepsgraphBuilderCache()
{
}
DepsgraphBuilderCache::~DepsgraphBuilderCache()
{
for (AnimatedPropertyStorageMap::value_type &iter : animated_property_storage_map_) {
AnimatedPropertyStorage *animated_property_storage = iter.second;
OBJECT_GUARDED_DELETE(animated_property_storage, AnimatedPropertyStorage);
}
}
AnimatedPropertyStorage *DepsgraphBuilderCache::ensureAnimatedPropertyStorage(ID *id)
{
AnimatedPropertyStorageMap::iterator it = animated_property_storage_map_.find(id);
if (it != animated_property_storage_map_.end()) {
return it->second;
}
AnimatedPropertyStorage *animated_property_storage = OBJECT_GUARDED_NEW(AnimatedPropertyStorage);
animated_property_storage_map_.insert(make_pair(id, animated_property_storage));
return animated_property_storage;
}
AnimatedPropertyStorage *DepsgraphBuilderCache::ensureInitializedAnimatedPropertyStorage(ID *id)
{
AnimatedPropertyStorage *animated_property_storage = ensureAnimatedPropertyStorage(id);
if (!animated_property_storage->is_fully_initialized) {
animated_property_storage->initializeFromID(this, id);
animated_property_storage->is_fully_initialized = true;
}
return animated_property_storage;
}
} // namespace DEG

View File

@ -0,0 +1,103 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2018 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup depsgraph
*/
#pragma once
#include "intern/depsgraph_type.h"
#include "RNA_access.h"
struct ID;
struct PointerRNA;
struct PropertyRNA;
namespace DEG {
class DepsgraphBuilderCache;
/* Identifier for animated property. */
class AnimatedPropertyID {
public:
AnimatedPropertyID();
AnimatedPropertyID(const PointerRNA *pointer_rna, const PropertyRNA *property_rna);
AnimatedPropertyID(const PointerRNA &pointer_rna, const PropertyRNA *property_rna);
AnimatedPropertyID(ID *id, StructRNA *type, const char *property_name);
AnimatedPropertyID(ID *id, StructRNA *type, void *data, const char *property_name);
bool operator<(const AnimatedPropertyID &other) const;
/* Corresponds to PointerRNA.data. */
void *data;
const PropertyRNA *property_rna;
};
class AnimatedPropertyStorage {
public:
AnimatedPropertyStorage();
void initializeFromID(DepsgraphBuilderCache *builder_cache, ID *id);
void tagPropertyAsAnimated(const AnimatedPropertyID &property_id);
void tagPropertyAsAnimated(const PointerRNA *pointer_rna, const PropertyRNA *property_rna);
bool isPropertyAnimated(const AnimatedPropertyID &property_id);
bool isPropertyAnimated(const PointerRNA *pointer_rna, const PropertyRNA *property_rna);
/* The storage is fully initialized from all F-Curves from corresponding ID. */
bool is_fully_initialized;
/* indexed by PointerRNA.data. */
set<AnimatedPropertyID> animated_properties_set;
};
typedef map<ID *, AnimatedPropertyStorage *> AnimatedPropertyStorageMap;
/* Cached data which can be re-used by multiple builders. */
class DepsgraphBuilderCache {
public:
DepsgraphBuilderCache();
~DepsgraphBuilderCache();
/* Makes sure storage for animated properties exists and initialized for the given ID. */
AnimatedPropertyStorage *ensureAnimatedPropertyStorage(ID *id);
AnimatedPropertyStorage *ensureInitializedAnimatedPropertyStorage(ID *id);
/* Shortcuts to go through ensureInitializedAnimatedPropertyStorage and its
* isPropertyAnimated.
*
* NOTE: Avoid using for multiple subsequent lookups, query for the storage once, and then query
* the storage.
*
* TODO(sergey): Technically, this makes this class something else than just a cache, but what is
* the better name? */
template<typename... Args> bool isPropertyAnimated(ID *id, Args... args)
{
AnimatedPropertyStorage *animated_property_storage = ensureInitializedAnimatedPropertyStorage(
id);
return animated_property_storage->isPropertyAnimated(args...);
}
AnimatedPropertyStorageMap animated_property_storage_map_;
};
} // namespace DEG

View File

@ -129,8 +129,10 @@ void free_copy_on_write_datablock(void *id_info_v)
/* **** General purpose functions **** */
DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph)
: DepsgraphBuilder(bmain, graph),
DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain,
Depsgraph *graph,
DepsgraphBuilderCache *cache)
: DepsgraphBuilder(bmain, graph, cache),
scene_(NULL),
view_layer_(NULL),
view_layer_index_(-1),

View File

@ -69,6 +69,7 @@ namespace DEG {
struct ComponentNode;
struct Depsgraph;
class DepsgraphBuilderCache;
struct IDNode;
struct Node;
struct OperationNode;
@ -76,7 +77,7 @@ struct TimeSourceNode;
class DepsgraphNodeBuilder : public DepsgraphBuilder {
public:
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache);
~DepsgraphNodeBuilder();
/* For given original ID get ID which is created by CoW system. */

View File

@ -209,8 +209,10 @@ static bool bone_has_segments(Object *object, const char *bone_name)
/* **** General purpose functions **** */
DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph)
: DepsgraphBuilder(bmain, graph), scene_(NULL), rna_node_query_(graph)
DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain,
Depsgraph *graph,
DepsgraphBuilderCache *cache)
: DepsgraphBuilder(bmain, graph, cache), scene_(NULL), rna_node_query_(graph, this)
{
}

View File

@ -86,6 +86,7 @@ namespace DEG {
struct ComponentNode;
struct DepsNodeHandle;
struct Depsgraph;
class DepsgraphBuilderCache;
struct IDNode;
struct Node;
struct OperationNode;
@ -155,7 +156,7 @@ struct RNAPathKey {
class DepsgraphRelationBuilder : public DepsgraphBuilder {
public:
DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph);
DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache);
void begin_build();

View File

@ -45,6 +45,7 @@ extern "C" {
#include "RNA_access.h"
#include "intern/depsgraph.h"
#include "intern/builder/deg_builder.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_id.h"
@ -130,8 +131,10 @@ void ghash_id_data_free_func(void *value)
} // namespace
RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph)
: depsgraph_(depsgraph), id_data_map_(BLI_ghash_ptr_new("rna node query id data hash"))
RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder)
: depsgraph_(depsgraph),
builder_(builder),
id_data_map_(BLI_ghash_ptr_new("rna node query id data hash"))
{
}

View File

@ -36,6 +36,7 @@ namespace DEG {
struct Depsgraph;
struct Node;
class RNANodeQueryIDData;
class DepsgraphBuilder;
/* For queries which gives operation node or key defines whether we are
* interested in a result of the given property or whether we are linking some
@ -72,13 +73,14 @@ class RNANodeIdentifier {
* dependency graph which satisfies given RNA pointer or RAN path. */
class RNANodeQuery {
public:
RNANodeQuery(Depsgraph *depsgraph);
RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder);
~RNANodeQuery();
Node *find_node(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source);
protected:
Depsgraph *depsgraph_;
DepsgraphBuilder *builder_;
/* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */
GHash *id_data_map_;

View File

@ -46,6 +46,7 @@ extern "C" {
#include "DEG_depsgraph_build.h"
#include "builder/deg_builder.h"
#include "builder/deg_builder_cache.h"
#include "builder/deg_builder_cycle.h"
#include "builder/deg_builder_nodes.h"
#include "builder/deg_builder_relations.h"
@ -238,14 +239,15 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph,
BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1);
BLI_assert(deg_graph->scene == scene);
BLI_assert(deg_graph->view_layer == view_layer);
DEG::DepsgraphBuilderCache builder_cache;
/* Generate all the nodes in the graph first */
DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph);
DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph, &builder_cache);
node_builder.begin_build();
node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
node_builder.end_build();
/* Hook up relationships between operations - to determine evaluation
* order. */
DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph);
DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache);
relation_builder.begin_build();
relation_builder.build_view_layer(scene, view_layer);
relation_builder.build_copy_on_write_relations();