Files
blender/source/blender/depsgraph/intern/depsnode.cc
Sergey Sharybin 86a57b04bf Depsgraph: Store node input/output links in a vector rather than in set
Set is much slower to iterate through (due to cache misses and such) and
the only advantage of using set is faster removal of link. However, we are
iterating links much much more often than removing them, and even when we
are removing links we don't really need to remove link from nodes which it
connects -- we don't support partial depsgraph updates, so removing links
from nodes on destruction is a waste of time.

If we ever want to support partial updates we can have dedicated function
to remove link from nodes it connects.

This gives a surprising increase of fps from 42 to 56 with test file from
Mr. J.P.Bouza (blenrig_for_debugging.blend). Surprising because old DEG is
actually slower here (52 fps). Didn't see any regressions (and don't see
why they will happen), so let's ask our riggers and animators to perform
further speed tests ;)
2016-05-09 12:42:53 +02:00

312 lines
8.4 KiB
C++

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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) 2013 Blender Foundation.
* All rights reserved.
*
* Original Author: Joshua Leung
* Contributor(s): None Yet
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/depsgraph/intern/depsnode.cc
* \ingroup depsgraph
*/
#include <stdio.h>
#include <string.h>
#include "BLI_utildefines.h"
extern "C" {
#include "DNA_ID.h"
#include "DNA_anim_types.h"
#include "BKE_animsys.h"
#include "DEG_depsgraph.h"
}
#include "depsnode.h" /* own include */
#include "depsnode_component.h"
#include "depsnode_operation.h"
#include "depsgraph_intern.h"
/* *************** */
/* Node Management */
/* Add ------------------------------------------------ */
DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
{
this->type = type;
if (type == DEPSNODE_TYPE_OPERATION)
this->tclass = DEPSNODE_CLASS_OPERATION;
else if (type < DEPSNODE_TYPE_PARAMETERS)
this->tclass = DEPSNODE_CLASS_GENERIC;
else
this->tclass = DEPSNODE_CLASS_COMPONENT;
this->tname = tname;
}
DepsNode::DepsNode()
{
this->name[0] = '\0';
}
DepsNode::~DepsNode()
{
/* Free links. */
/* NOTE: We only free incoming links. This is to avoid double-free of links
* when we're trying to free same link from both it's sides. We don't have
* dangling links so this is not a problem from memory leaks point of view.
*/
DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
{
OBJECT_GUARDED_DELETE(rel, DepsRelation);
}
DEPSNODE_RELATIONS_ITER_END;
}
/* Generic identifier for Depsgraph Nodes. */
string DepsNode::identifier() const
{
char typebuf[7];
sprintf(typebuf, "(%d)", type);
return string(typebuf) + " : " + name;
}
/* ************* */
/* Generic Nodes */
/* Time Source Node ============================================== */
void TimeSourceDepsNode::tag_update(Depsgraph *graph)
{
for (DepsNode::Relations::const_iterator it = outlinks.begin();
it != outlinks.end();
++it)
{
DepsRelation *rel = *it;
DepsNode *node = rel->to;
node->tag_update(graph);
}
}
/* Root Node ============================================== */
RootDepsNode::RootDepsNode() : scene(NULL), time_source(NULL)
{
}
RootDepsNode::~RootDepsNode()
{
OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
}
TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
{
if (!time_source) {
DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
/*time_source->owner = this;*/ // XXX
}
return time_source;
}
DEG_DEPSNODE_DEFINE(RootDepsNode, DEPSNODE_TYPE_ROOT, "Root DepsNode");
static DepsNodeFactoryImpl<RootDepsNode> DNTI_ROOT;
/* Time Source Node ======================================= */
DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEPSNODE_TYPE_TIMESOURCE, "Time Source");
static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
/* ID Node ================================================ */
/* Initialize 'id' node - from pointer data given. */
void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
{
/* Store ID-pointer. */
BLI_assert(id != NULL);
this->id = (ID *)id;
this->layers = (1 << 20) - 1;
this->eval_flags = 0;
/* NOTE: components themselves are created if/when needed.
* This prevents problems with components getting added
* twice if an ID-Ref needs to be created to house it...
*/
}
/* Free 'id' node. */
IDDepsNode::~IDDepsNode()
{
clear_components();
}
/* Copy 'id' node. */
void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src)
{
(void)src; /* Ignored. */
/* Iterate over items in original hash, adding them to new hash. */
for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin();
it != this->components.end();
++it)
{
/* Get current <type : component> mapping. */
ComponentIDKey c_key = it->first;
DepsNode *old_component = it->second;
/* Make a copy of component. */
ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component);
/* Add new node to hash... */
this->components[c_key] = component;
}
// TODO: perform a second loop to fix up links?
BLI_assert(!"Not expected to be used");
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
const string &name) const
{
ComponentIDKey key(type, name);
ComponentMap::const_iterator it = components.find(key);
return it != components.end() ? it->second : NULL;
}
ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
const string &name)
{
ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (!comp_node) {
DepsNodeFactory *factory = DEG_get_node_factory(type);
comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
/* Register. */
this->components[key] = comp_node;
comp_node->owner = this;
}
return comp_node;
}
void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
{
ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (comp_node) {
/* Unregister. */
this->components.erase(key);
OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
}
}
void IDDepsNode::clear_components()
{
for (ComponentMap::const_iterator it = components.begin();
it != components.end();
++it)
{
ComponentDepsNode *comp_node = it->second;
OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
}
components.clear();
}
void IDDepsNode::tag_update(Depsgraph *graph)
{
for (ComponentMap::const_iterator it = components.begin();
it != components.end();
++it)
{
ComponentDepsNode *comp_node = it->second;
/* TODO(sergey): What about drievrs? */
bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
AnimData *adt = BKE_animdata_from_id(id);
/* Animation data might be null if relations are tagged for update. */
if (adt != NULL && (adt->recalc & ADT_RECALC_ANIM)) {
do_component_tag = true;
}
}
if (do_component_tag) {
comp_node->tag_update(graph);
}
}
}
DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF;
/* Subgraph Node ========================================== */
/* Initialize 'subgraph' node - from pointer data given. */
void SubgraphDepsNode::init(const ID *id, const string &UNUSED(subdata))
{
/* Store ID-ref if provided. */
this->root_id = (ID *)id;
/* NOTE: graph will need to be added manually,
* as we don't have any way of passing this down.
*/
}
/* Free 'subgraph' node */
SubgraphDepsNode::~SubgraphDepsNode()
{
/* Only free if graph not shared, of if this node is the first
* reference to it...
*/
// XXX: prune these flags a bit...
if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
/* Free the referenced graph. */
DEG_graph_free(this->graph);
this->graph = NULL;
}
}
/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */
void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
const SubgraphDepsNode * /*src*/)
{
//const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src;
//SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst;
/* for now, subgraph itself isn't copied... */
BLI_assert(!"Not expected to be used");
}
DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
void DEG_register_base_depsnodes()
{
DEG_register_node_typeinfo(&DNTI_ROOT);
DEG_register_node_typeinfo(&DNTI_TIMESOURCE);
DEG_register_node_typeinfo(&DNTI_ID_REF);
DEG_register_node_typeinfo(&DNTI_SUBGRAPH);
}