Depsgraph: New dependency graph integration commit

This commit integrates the work done so far on the new dependency graph system,
where goal was to replace legacy depsgraph with the new one, supporting loads of
neat features like:

- More granular dependency relation nature, which solves issues with fake cycles
  in the dependencies.

- Move towards all-animatable, by better integration of drivers into the system.

- Lay down some basis for upcoming copy-on-write, overrides and so on.

The new system is living side-by-side with the previous one and disabled by
default, so nothing will become suddenly broken. The way to enable new depsgraph
is to pass `--new-depsgraph` command line argument.

It's a bit early to consider the system production-ready, there are some TODOs
and issues were discovered during the merge period, they'll be addressed ASAP.
But it's important to merge, because it's the only way to attract artists to
really start testing this system.

There are number of assorted documents related on the design of the new system:

* http://wiki.blender.org/index.php/User:Aligorith/GSoC2013_Depsgraph#Design_Documents
* http://wiki.blender.org/index.php/User:Nazg-gul/DependencyGraph

There are also some user-related information online:

* http://code.blender.org/2015/02/blender-dependency-graph-branch-for-users/
* http://code.blender.org/2015/03/more-dependency-graph-tricks/

Kudos to everyone who was involved into the project:

- Joshua "Aligorith" Leung -- design specification, initial code
- Lukas "lukas_t" Toenne -- integrating code into blender, with further fixes
- Sergey "Sergey" "Sharybin" -- some mocking around, trying to wrap up the
  project and so
- Bassam "slikdigit" Kurdali -- stressing the new system, reporting all the
  issues and recording/writing documentation.
- Everyone else who i forgot to mention here :)
This commit is contained in:
Sergey Sharybin 2015-05-12 15:05:57 +05:00
parent a09341469e
commit bac7353801
133 changed files with 11844 additions and 58 deletions

@ -449,6 +449,9 @@ endif()
option(WITH_CPP11 "Build with C++11 standard enabled, for development use only!" OFF)
mark_as_advanced(WITH_CPP11)
# Dependency graph
option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON)
# avoid using again
option_defaults_clear()

@ -524,6 +524,7 @@ macro(SETUP_BLENDER_SORTED_LIBS)
bf_blenloader
bf_imbuf
bf_blenlib
bf_depsgraph
bf_intern_ghost
bf_intern_string
bf_avi

@ -372,7 +372,7 @@ def propose_priorities():
def creator(env):
sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/depsgraph', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
defs = []

@ -199,7 +199,7 @@ def validate_arguments(args, bc):
'LLIBS', 'PLATFORM_LINKFLAGS', 'MACOSX_ARCHITECTURE', 'MACOSX_SDK', 'XCODE_CUR_VER', 'C_COMPILER_ID',
'BF_CYCLES_CUDA_BINARIES_ARCH', 'BF_PROGRAM_LINKFLAGS', 'MACOSX_DEPLOYMENT_TARGET',
'WITH_BF_CYCLES_DEBUG', 'WITH_BF_CYCLES_LOGGING',
'WITH_BF_CPP11'
'WITH_BF_CPP11', 'WITH_BF_LEGACY_DEPSGRAPH',
]
@ -657,6 +657,8 @@ def read_opts(env, cfg, args):
('BF_PROGRAM_LINKFLAGS', 'Link flags applied only to final binaries (blender and blenderplayer, not makesrna/makesdna)', ''),
(BoolVariable('WITH_BF_CPP11', '"Build with C++11 standard enabled, for development use only!', False)),
(BoolVariable('WITH_BF_LEGACY_DEPSGRAPH', 'Build Blender with legacy dependency graph', True)),
) # end of opts.AddOptions()
return localopts

@ -102,6 +102,7 @@ add_subdirectory(bmesh)
add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blenloader)
add_subdirectory(depsgraph)
add_subdirectory(ikplugin)
add_subdirectory(physics)
add_subdirectory(gpu)

@ -33,6 +33,7 @@ SConscript(['avi/SConscript',
'blenkernel/SConscript',
'blenlib/SConscript',
'blenloader/SConscript',
'depsgraph/SConscript',
'gpu/SConscript',
'editors/SConscript',
'imbuf/SConscript',

@ -92,6 +92,7 @@ void DAG_exit(void);
*/
void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce);
void DAG_relations_tag_update(struct Main *bmain);
void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
void DAG_scene_free(struct Scene *sce);

@ -43,6 +43,7 @@ struct bArmature;
struct Main;
struct ModifierData;
struct BMEditMesh;
struct DepsNodeHandle;
typedef enum {
/* Should not be used, only for None modifier type */
@ -260,6 +261,17 @@ typedef struct ModifierTypeInfo {
struct Main *bmain, struct Scene *scene,
struct Object *ob, struct DagNode *obNode);
/* Add the appropriate relations to the dependency graph.
*
* This function is optional.
*/
/* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */
void (*updateDepsgraph)(struct ModifierData *md,
struct Main *bmain,
struct Scene *scene,
struct Object *ob,
struct DepsNodeHandle *node);
/* Should return true if the modifier needs to be recalculated on time
* changes.
*

@ -28,6 +28,7 @@ set(INC
../blenfont
../blenlib
../blenloader
../depsgraph
../gpu
../ikplugin
../imbuf
@ -482,4 +483,8 @@ endif()
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
if(WITH_LEGACY_DEPSGRAPH)
add_definitions(-DWITH_LEGACY_DEPSGRAPH)
endif()
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}")

@ -58,6 +58,7 @@ incs = [
'../blenlib',
'../blenloader',
'../bmesh',
'../depsgraph',
'../gpu',
'../ikplugin',
'../imbuf',
@ -175,6 +176,9 @@ if env['WITH_BF_BINRELOC']:
incs += ' #extern/binreloc/include'
defs.append('WITH_BINRELOC')
if env['WITH_BF_LEGACY_DEPSGRAPH']:
defs.append('WITH_LEGACY_DEPSGRAPH')
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [166,25]) #, cc_compileflags = env['CCFLAGS'].append('/WX') )
else:

@ -54,6 +54,7 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@ -1318,9 +1319,13 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
}
/* Tag pose for recalc. Also tag all related data to be recalc. */
void BKE_pose_tag_recalc(Main *UNUSED(bmain), bPose *pose)
void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
{
pose->flag |= POSE_RECALC;
/* Depsgraph components depends on actual pose state,
* if pose was changed depsgraph is to be updated as well.
*/
DAG_relations_tag_update(bmain);
}
/* For the calculation of the effects of an Action at the given frame on an object

@ -51,6 +51,8 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "DEG_depsgraph.h"
#ifdef WITH_LEGACY_DEPSGRAPH
# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
#else

@ -88,16 +88,25 @@
#include "depsgraph_private.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_query.h"
#ifdef WITH_LEGACY_DEPSGRAPH
static SpinLock threaded_update_lock;
void DAG_init(void)
{
BLI_spin_init(&threaded_update_lock);
DEG_register_node_types();
}
void DAG_exit(void)
{
BLI_spin_end(&threaded_update_lock);
DEG_free_node_types();
}
/* Queue and stack operations for dag traversal
@ -1329,8 +1338,14 @@ static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NU
void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), void (*scene_func)(Main *bmain, Scene *scene, int updated))
{
EditorsUpdateIDCb = id_func;
EditorsUpdateSceneCb = scene_func;
if (DEG_depsgraph_use_legacy()) {
EditorsUpdateIDCb = id_func;
EditorsUpdateSceneCb = scene_func;
}
else {
/* New dependency graph. */
DEG_editors_set_update_cb(id_func, scene_func);
}
}
static void dag_editors_id_update(Main *bmain, ID *id)
@ -1529,7 +1544,7 @@ static void dag_scene_build(Main *bmain, Scene *sce)
Base *base;
BLI_listbase_clear(&tempbase);
build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
dag_check_cycle(sce->theDag);
@ -1621,32 +1636,65 @@ static void dag_scene_build(Main *bmain, Scene *sce)
/* clear all dependency graphs */
void DAG_relations_tag_update(Main *bmain)
{
Scene *sce;
for (sce = bmain->scene.first; sce; sce = sce->id.next)
dag_scene_free(sce);
if (DEG_depsgraph_use_legacy()) {
Scene *sce;
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
dag_scene_free(sce);
}
}
else {
/* New dependency graph. */
DEG_relations_tag_update(bmain);
}
}
/* rebuild dependency graph only for a given scene */
void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
{
dag_scene_free(sce);
DAG_scene_relations_update(bmain, sce);
if (DEG_depsgraph_use_legacy()) {
dag_scene_free(sce);
DAG_scene_relations_update(bmain, sce);
}
else {
/* New dependency graph. */
DEG_scene_relations_rebuild(bmain, sce);
}
}
/* create dependency graph if it was cleared or didn't exist yet */
void DAG_scene_relations_update(Main *bmain, Scene *sce)
{
if (!sce->theDag)
dag_scene_build(bmain, sce);
if (DEG_depsgraph_use_legacy()) {
if (!sce->theDag)
dag_scene_build(bmain, sce);
}
else {
/* New dependency graph. */
DEG_scene_relations_update(bmain, sce);
}
}
void DAG_scene_relations_validate(Main *bmain, Scene *sce)
{
if (!DEG_depsgraph_use_legacy()) {
DEG_debug_scene_relations_validate(bmain, sce);
}
}
void DAG_scene_free(Scene *sce)
{
if (sce->theDag) {
free_forest(sce->theDag);
MEM_freeN(sce->theDag);
sce->theDag = NULL;
if (DEG_depsgraph_use_legacy()) {
if (sce->theDag) {
free_forest(sce->theDag);
MEM_freeN(sce->theDag);
sce->theDag = NULL;
}
}
else {
if (sce->depsgraph) {
DEG_graph_free(sce->depsgraph);
sce->depsgraph = NULL;
}
}
}
@ -1889,7 +1937,11 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
DagAdjList *itA;
Object *ob;
int lasttime;
if (!DEG_depsgraph_use_legacy()) {
return;
}
if (sce->theDag == NULL) {
printf("DAG zero... not allowed to happen!\n");
DAG_scene_relations_update(bmain, sce);
@ -2300,7 +2352,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb)
}
}
static void dag_group_on_visible_update(Group *group)
static void dag_group_on_visible_update(Scene *scene, Group *group)
{
GroupObject *go;
@ -2322,7 +2374,7 @@ static void dag_group_on_visible_update(Group *group)
}
if (go->ob->dup_group)
dag_group_on_visible_update(go->ob->dup_group);
dag_group_on_visible_update(scene, go->ob->dup_group);
}
}
@ -2330,7 +2382,13 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
{
ListBase listbase;
DagSceneLayer *dsl;
if (!DEG_depsgraph_use_legacy()) {
/* Inform new dependnecy graphs about visibility changes. */
DEG_on_visible_update(bmain, do_time);
return;
}
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@ -2357,7 +2415,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
oblay = (node) ? node->lay : ob->lay;
if ((oblay & lay) & ~scene->lay_updated) {
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
/* TODO(sergey): Why do we need armature here now but didn't need before? */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) {
ob->recalc |= OB_RECALC_DATA;
lib_id_recalc_tag(bmain, &ob->id);
}
@ -2375,7 +2434,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
lib_id_recalc_tag(bmain, &ob->id);
}
if (ob->dup_group)
dag_group_on_visible_update(ob->dup_group);
dag_group_on_visible_update(scene, ob->dup_group);
}
}
@ -2609,7 +2668,12 @@ void DAG_ids_flush_tagged(Main *bmain)
ListBase *lbarray[MAX_LIBARRAY];
int a;
bool do_flush = false;
if (!DEG_depsgraph_use_legacy()) {
DEG_ids_flush_tagged(bmain);
return;
}
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@ -2653,6 +2717,11 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
int a;
bool updated = false;
if (!DEG_depsgraph_use_legacy()) {
DEG_ids_check_recalc(bmain, scene, time);
return;
}
/* loop over all ID types */
a = set_listbasepointers(bmain, lbarray);
@ -2769,6 +2838,11 @@ void DAG_ids_clear_recalc(Main *bmain)
void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
{
if (!DEG_depsgraph_use_legacy()) {
DEG_id_tag_update_ex(bmain, id, flag);
return;
}
if (id == NULL) return;
if (G.debug & G_DEBUG_DEPSGRAPH) {
@ -3160,6 +3234,10 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object)
{
DagNode *node;
if (!DEG_depsgraph_use_legacy()) {
return DEG_get_eval_flags_for_id(scene->depsgraph, (ID*)object);
}
if (scene->theDag == NULL) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
@ -3198,3 +3276,286 @@ bool DAG_is_acyclic(Scene *scene)
{
return scene->theDag->is_acyclic;
}
#else
/* *********************************************************************
* Stubs to avoid linking issues and make sure legacy crap is not used *
* *********************************************************************
*/
DagNodeQueue *queue_create(int UNUSED(slots))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
void queue_raz(DagNodeQueue *UNUSED(queue))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
void queue_delete(DagNodeQueue *UNUSED(queue))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
DagNode *pop_queue(DagNodeQueue *UNUSED(queue))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
DagForest *dag_init(void)
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
DagForest *build_dag(Main *UNUSED(bmain),
Scene *UNUSED(sce),
short UNUSED(mask))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
void free_forest(DagForest *UNUSED(Dag))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
void dag_add_relation(DagForest *UNUSED(forest),
DagNode *UNUSED(fob1),
DagNode *UNUSED(fob2),
short UNUSED(rel),
const char *UNUSED(name))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
/* debug test functions */
void graph_print_queue(DagNodeQueue *UNUSED(nqueue))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
void graph_print_adj_list(DagForest *UNUSED(dag))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
void DAG_scene_flush_update(Main *UNUSED(bmain),
Scene *UNUSED(sce),
unsigned int UNUSED(lay),
const short UNUSED(time))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
void DAG_scene_update_flags(Main *UNUSED(bmain),
Scene *UNUSED(scene),
unsigned int UNUSED(lay),
const bool UNUSED(do_time),
const bool UNUSED(do_invisible_flush))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
/* ******************* DAG FOR ARMATURE POSE ***************** */
void DAG_pose_sort(Object *UNUSED(ob))
{
BLI_assert(!"Should not be used with new dependnecy graph");
}
/* ************************ DAG FOR THREADED UPDATE ********************* */
void DAG_threaded_update_begin(Scene *UNUSED(scene),
void (*func)(void *node, void *user_data),
void *UNUSED(user_data))
{
BLI_assert(!"Should not be used with new dependnecy graph");
(void)func;
}
void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v),
void (*func)(void *node, void *user_data),
void *UNUSED(user_data))
{
BLI_assert(!"Should not be used with new dependnecy graph");
(void)func;
}
/* ************************ DAG querying ********************* */
Object *DAG_get_node_object(void *UNUSED(node_v))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return NULL;
}
const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return "INVALID";
}
bool DAG_is_acyclic(Scene *UNUSED(scene))
{
BLI_assert(!"Should not be used with new dependnecy graph");
return false;
}
/* ************************************
* This functions are to be supported *
* ************************************
*/
void DAG_init(void)
{
DEG_register_node_types();
}
void DAG_exit(void)
{
DEG_free_node_types();
}
/* ************************ API *********************** */
void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func,
DEG_EditorUpdateSceneCb scene_func)
{
DEG_editors_set_update_cb(id_func, scene_func);
}
/* Tag all relations for update. */
void DAG_relations_tag_update(Main *bmain)
{
DEG_relations_tag_update(bmain);
}
/* Rebuild dependency graph only for a given scene. */
void DAG_scene_relations_rebuild(Main *bmain, Scene *scene)
{
DEG_scene_relations_rebuild(bmain, scene);
}
/* Create dependency graph if it was cleared or didn't exist yet. */
void DAG_scene_relations_update(Main *bmain, Scene *scene)
{
DEG_scene_relations_update(bmain, scene);
}
void DAG_scene_relations_validate(Main *bmain, Scene *scene)
{
DEG_debug_scene_relations_validate(bmain, scene);
}
void DAG_scene_free(Scene *scene)
{
DEG_scene_graph_free(scene);
}
void DAG_on_visible_update(Main *bmain, const bool do_time)
{
DEG_on_visible_update(bmain, do_time);
}
void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
{
DEG_ids_check_recalc(bmain, scene, time);
}
void DAG_id_tag_update(ID *id, short flag)
{
DEG_id_tag_update_ex(G.main, id, flag);
}
void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
{
DEG_id_tag_update_ex(bmain, id, flag);
}
void DAG_id_type_tag(Main *bmain, short idtype)
{
DEG_id_type_tag(bmain, idtype);
}
int DAG_id_type_tagged(Main *bmain, short idtype)
{
return DEG_id_type_tagged(bmain, idtype);
}
void DAG_ids_clear_recalc(Main *bmain)
{
DEG_ids_clear_recalc(bmain);
}
short DAG_get_eval_flags_for_object(Scene *scene, void *object)
{
return DEG_get_eval_flags_for_id(scene->depsgraph, (ID*)object);
}
void DAG_ids_flush_tagged(Main *bmain)
{
DEG_ids_flush_tagged(bmain);
}
/* ************************ DAG DEBUGGING ********************* */
void DAG_print_dependencies(Main *UNUSED(bmain),
Scene *scene,
Object *UNUSED(ob))
{
DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false);
}
#endif

@ -115,6 +115,8 @@
#include "BKE_texture.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
#include "RNA_access.h"
#ifdef WITH_PYTHON
@ -1081,8 +1083,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext),
"EvaluationContext");
bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
BLI_spin_init((SpinLock *)bmain->lock);
return bmain;
@ -1149,7 +1150,7 @@ void BKE_main_free(Main *mainvar)
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
MEM_freeN(mainvar->eval_ctx);
DEG_evaluation_context_free(mainvar->eval_ctx);
MEM_freeN(mainvar);
}

@ -61,6 +61,7 @@
#include "BKE_object.h"
#include "BKE_editmesh.h"
#include "DEG_depsgraph.h"
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
@ -2397,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object(
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
EvaluationContext eval_ctx = {0};
eval_ctx.mode = DAG_EVAL_RENDER;
EvaluationContext eval_ctx;
DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);

@ -57,6 +57,8 @@
#include "BKE_material.h"
#include "BKE_image.h"
#include "DEG_depsgraph.h"
#ifdef WITH_LEGACY_DEPSGRAPH
# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
#else

@ -89,6 +89,8 @@
#include "BKE_unit.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
#include "RE_engine.h"
#include "PIL_time.h"
@ -193,6 +195,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
scen->ed = NULL;
scen->theDag = NULL;
scen->depsgraph = NULL;
scen->obedit = NULL;
scen->stats = NULL;
scen->fps_info = NULL;
@ -431,6 +434,8 @@ void BKE_scene_free(Scene *sce)
}
DAG_scene_free(sce);
if (sce->depsgraph)
DEG_graph_free(sce->depsgraph);
if (sce->nodetree) {
ntreeFreeTree(sce->nodetree);
@ -1167,6 +1172,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
scene->r.cfra = (int)intpart;
}
#ifdef WITH_LEGACY_DEPSGRAPH
/* drivers support/hacks
* - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
* - these are always run since the depsgraph can't handle non-object data
@ -1267,6 +1273,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen
}
}
}
#endif /* WITH_LEGACY_DEPSGRAPH */
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
@ -1318,7 +1325,12 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
* would pollute STDERR with whole bunch of timing information which then
* could be parsed and nicely visualized.
*/
#undef DETAILED_ANALYSIS_OUTPUT
#ifdef WITH_LEGACY_DEPSGRAPH
# undef DETAILED_ANALYSIS_OUTPUT
#else
/* ALWAYS KEEY DISABLED! */
# undef DETAILED_ANALYSIS_OUTPUT
#endif
/* Mballs evaluation uses BKE_scene_base_iter_next which calls
* duplilist for all objects in the scene. This leads to conflict
@ -1330,6 +1342,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
*/
#define MBALL_SINGLETHREAD_HACK
#ifdef WITH_LEGACY_DEPSGRAPH
typedef struct StatisicsEntry {
struct StatisicsEntry *next, *prev;
Object *object;
@ -1619,6 +1632,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma
BKE_mask_update_scene(bmain, scene);
}
#endif /* WITH_LEGACY_DEPSGRAPH */
static bool check_rendered_viewport_visible(Main *bmain)
{
@ -1670,13 +1684,26 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
{
Scene *sce_iter;
#ifdef WITH_LEGACY_DEPSGRAPH
bool use_new_eval = !DEG_depsgraph_use_legacy();
#endif
/* keep this first */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
/* (re-)build dependency graph if needed */
for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
DAG_scene_relations_update(bmain, sce_iter);
/* Uncomment this to check if graph was properly tagged for update. */
#if 0
#ifdef WITH_LEGACY_DEPSGRAPH
if (use_new_eval)
#endif
{
DAG_scene_relations_validate(bmain, sce_iter);
}
#endif
}
/* flush editing data if needed */
prepare_mesh_for_viewport_render(bmain, scene);
@ -1697,7 +1724,17 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
*
* in the future this should handle updates for all datablocks, not
* only objects and scenes. - brecht */
scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
#ifdef WITH_LEGACY_DEPSGRAPH
if (use_new_eval) {
DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
}
else {
scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
}
#else
DEG_evaluate_on_refresh(eval_ctx, bmain, scene->depsgraph, scene);
#endif
/* update sound system animation (TODO, move to depsgraph) */
BKE_sound_update_scene(bmain, scene);
@ -1715,7 +1752,8 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
* Need to do this so changing material settings from the graph/dopesheet
* will update stuff in the viewport.
*/
if (DAG_id_type_tagged(bmain, ID_MA)) {
#ifdef WITH_LEGACY_DEPSGRAPH
if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
Material *material;
float ctime = BKE_scene_frame_get(scene);
@ -1730,7 +1768,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
/* Also do the same for node trees. */
if (DAG_id_type_tagged(bmain, ID_NT)) {
if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
float ctime = BKE_scene_frame_get(scene);
FOREACH_NODETREE(bmain, ntree, id)
@ -1741,9 +1779,12 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
FOREACH_NODETREE_END
}
#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
/* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, scene, false);
/* clear recalc flags */
@ -1763,6 +1804,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
#ifdef DETAILED_ANALYSIS_OUTPUT
double start_time = PIL_check_seconds_timer();
#endif
#ifdef WITH_LEGACY_DEPSGRAPH
bool use_new_eval = !DEG_depsgraph_use_legacy();
#else
/* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */
(void) do_invisible_flush;
#endif
/* keep this first */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
@ -1772,12 +1819,16 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* call this at the start so modifiers with textures don't lag 1 frame */
BKE_image_update_frame(bmain, sce->r.cfra);
#ifdef WITH_LEGACY_DEPSGRAPH
/* rebuild rigid body worlds before doing the actual frame update
* this needs to be done on start frame but animation playback usually starts one frame later
* we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
*/
scene_rebuild_rbw_recursive(sce, ctime);
if (!use_new_eval) {
scene_rebuild_rbw_recursive(sce, ctime);
}
#endif
BKE_sound_set_cfra(sce->r.cfra);
/* clear animation overrides */
@ -1786,14 +1837,18 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
DAG_scene_relations_update(bmain, sce_iter);
/* flush recalc flags to dependencies, if we were only changing a frame
* this would not be necessary, but if a user or a script has modified
* some datablock before BKE_scene_update_tagged was called, we need the flush */
DAG_ids_flush_tagged(bmain);
#ifdef WITH_LEGACY_DEPSGRAPH
if (!use_new_eval) {
/* flush recalc flags to dependencies, if we were only changing a frame
* this would not be necessary, but if a user or a script has modified
* some datablock before BKE_scene_update_tagged was called, we need the flush */
DAG_ids_flush_tagged(bmain);
/* Following 2 functions are recursive
* so don't call within 'scene_update_tagged_recursive' */
DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
/* Following 2 functions are recursive
* so don't call within 'scene_update_tagged_recursive' */
DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
}
#endif
BKE_mask_evaluate_all_masks(bmain, ctime, true);
@ -1807,8 +1862,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* can be overridden by settings from Scene, which owns the Texture through a hierarchy
* such as Scene->World->MTex/Texture) can still get correctly overridden.
*/
BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
/*...done with recursive funcs */
#ifdef WITH_LEGACY_DEPSGRAPH
if (!use_new_eval) {
BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
/*...done with recursive funcs */
}
#endif
/* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later
* when trying to find materials with drivers that need evaluating [#32017]
@ -1818,19 +1877,38 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
/* run rigidbody sim */
/* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
scene_do_rb_simulation_recursive(sce, ctime);
#ifdef WITH_LEGACY_DEPSGRAPH
if (!use_new_eval) {
scene_do_rb_simulation_recursive(sce, ctime);
}
#endif
/* BKE_object_handle_update() on all objects, groups and sets */
scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
#ifdef WITH_LEGACY_DEPSGRAPH
if (use_new_eval) {
DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
}
else {
scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
}
#else
DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
#endif
/* update sound system animation (TODO, move to depsgraph) */
BKE_sound_update_scene(bmain, sce);
scene_depsgraph_hack(eval_ctx, sce, sce);
#ifdef WITH_LEGACY_DEPSGRAPH
if (!use_new_eval) {
scene_depsgraph_hack(eval_ctx, sce, sce);
}
#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
/* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, sce, true);
/* clear recalc flags */

@ -5567,6 +5567,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
SceneRenderLayer *srl;
sce->theDag = NULL;
sce->depsgraph = NULL;
sce->obedit = NULL;
sce->stats = NULL;
sce->fps_info = NULL;

@ -0,0 +1,116 @@
# ***** 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) 2014, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Joshua Leung, Lukas Toenne
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
./intern
./util
../blenkernel
../blenlib
../bmesh
../makesdna
../makesrna
../modifiers
../windowmanager
../../../intern/atomic
../../../intern/guardedalloc
)
set(INC_SYS
)
set(SRC
intern/depsgraph.cc
intern/depsnode.cc
intern/depsnode_component.cc
intern/depsnode_operation.cc
intern/depsgraph_build.cc
intern/depsgraph_build_nodes.cc
intern/depsgraph_build_relations.cc
intern/depsgraph_debug.cc
intern/depsgraph_eval.cc
intern/depsgraph_query.cc
intern/depsgraph_queue.cc
intern/depsgraph_tag.cc
intern/depsgraph_type_defines.cc
util/depsgraph_util_cycle.cc
util/depsgraph_util_pchanmap.cc
util/depsgraph_util_transitive.cc
DEG_depsgraph.h
DEG_depsgraph_build.h
DEG_depsgraph_debug.h
DEG_depsgraph_query.h
intern/depsgraph.h
intern/depsnode.h
intern/depsnode_component.h
intern/depsnode_operation.h
intern/depsnode_opcodes.h
intern/depsgraph_build.h
intern/depsgraph_debug.h
intern/depsgraph_intern.h
intern/depsgraph_queue.h
intern/depsgraph_types.h
util/depsgraph_util_cycle.h
util/depsgraph_util_function.h
util/depsgraph_util_hash.h
util/depsgraph_util_map.h
util/depsgraph_util_pchanmap.h
util/depsgraph_util_set.h
util/depsgraph_util_transitive.h
)
TEST_UNORDERED_MAP_SUPPORT()
if(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
add_definitions(-DDEG_STD_UNORDERED_MAP)
else()
if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
add_definitions(-DDEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
else()
add_definitions(-DDEG_NO_UNORDERED_MAP)
message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
endif()
endif()
else()
if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
add_definitions(-DDEG_TR1_UNORDERED_MAP)
else()
add_definitions(-DDEG_NO_UNORDERED_MAP)
message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
endif()
endif()
if(WITH_LEGACY_DEPSGRAPH)
add_definitions(-DWITH_LEGACY_DEPSGRAPH)
endif()
if(WITH_BOOST)
list(APPEND INC_SYS ${BOOST_INCLUDE_DIR})
add_definitions(-DHAVE_BOOST_FUNCTION_BINDINGS)
endif()
blender_add_lib(bf_depsgraph "${SRC}" "${INC}" "${INC_SYS}")

@ -0,0 +1,210 @@
/*
* ***** 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 *****
*
* Public API for Depsgraph
*/
#ifndef __DEG_DEPSGRAPH_H__
#define __DEG_DEPSGRAPH_H__
/* Dependency Graph
*
* The dependency graph tracks relations between various pieces of data in
* a Blender file, but mainly just those which make up scene data. It is used
* to determine the set of operations need to ensure that all data has been
* correctly evaluated in response to changes, based on dependencies and visibility
* of affected data.
*
*
* Evaluation Engine
*
* The evaluation takes the operation-nodes the Depsgraph has tagged for updating,
* and schedules them up for being evaluated/executed such that the all dependency
* relationship constraints are satisfied.
*/
/* ************************************************* */
/* Forward-defined typedefs for core types
* - These are used in all depsgraph code and by all callers of Depsgraph API...
*/
/* Dependency Graph */
typedef struct Depsgraph Depsgraph;
/* ------------------------------------------------ */
struct EvaluationContext;
struct Main;
struct PointerRNA;
struct PropertyRNA;
#ifdef __cplusplus
extern "C" {
#endif
bool DEG_depsgraph_use_legacy(void);
void DEG_depsgraph_switch_to_legacy(void);
void DEG_depsgraph_switch_to_new(void);
/* ************************************************ */
/* Depsgraph API */
/* CRUD ------------------------------------------- */
// Get main depsgraph instance from context!
/* Create new Depsgraph instance */
// TODO: what args are needed here? What's the building-graph entry point?
Depsgraph *DEG_graph_new(void);
/* Free Depsgraph itself and all its data */
void DEG_graph_free(Depsgraph *graph);
/* Node Types Registry ---------------------------- */
/* Register all node types */
void DEG_register_node_types(void);
/* Free node type registry on exit */
void DEG_free_node_types(void);
/* Update Tagging -------------------------------- */
/* Tag node(s) associated with states such as time and visibility */
void DEG_scene_update_flags(Depsgraph *graph, const bool do_time);
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(struct Main *bmain, struct Scene *scene);
/* Update all dependency graphs when visible scenes/layers changes. */
void DEG_on_visible_update(struct Main *bmain, const bool do_time);
/* Tag node(s) associated with changed data for later updates */
void DEG_graph_id_tag_update(struct Main *bmain,
Depsgraph *graph,
struct ID *id);
void DEG_graph_data_tag_update(Depsgraph *graph, const struct PointerRNA *ptr);
void DEG_graph_property_tag_update(Depsgraph *graph, const struct PointerRNA *ptr, const struct PropertyRNA *prop);
/* Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(struct ID *id, short flag);
void DEG_id_tag_update_ex(struct Main *bmain,
struct ID *id,
short flag);
/* Tag given ID type for update.
*
* Used by all sort of render engines to quickly check if
* IDs of a given type need to be checked for update.
*/
void DEG_id_type_tag(struct Main *bmain, short idtype);
void DEG_ids_clear_recalc(struct Main *bmain);
/* Update Flushing ------------------------------- */
/* Flush updates */
void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph);
/* Flush updates for all IDs */
void DEG_ids_flush_tagged(struct Main *bmain);
/* Check if something was changed in the database and inform
* editors about this.
*/
void DEG_ids_check_recalc(struct Main *bmain,
struct Scene *scene,
bool time);
/* Clear all update tags
* - For aborted updates, or after successful evaluation
*/
void DEG_graph_clear_tags(Depsgraph *graph);
/* ************************************************ */
/* Evaluation Engine API */
/* Evaluation Context ---------------------------- */
/* Create new evaluation context. */
struct EvaluationContext *DEG_evaluation_context_new(int mode);
/* Initialize evaluation context.
* Used by the areas which currently overrides the context or doesn't have
* access to a proper one.
*/
void DEG_evaluation_context_init(struct EvaluationContext *eval_ctx, int mode);
/* Free evaluation context. */
void DEG_evaluation_context_free(struct EvaluationContext *eval_ctx);
/* Graph Evaluation ----------------------------- */
/* Frame changed recalculation entry point
* < context_type: context to perform evaluation for
* < ctime: (frame) new frame to evaluate values on
*/
void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
struct Main *bmain,
Depsgraph *graph,
float ctime,
const int layer);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
* < layers: visible layers bitmask to update the graph for
*/
void DEG_evaluate_on_refresh_ex(struct EvaluationContext *eval_ctx,
Depsgraph *graph,
const int layers);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
*/
void DEG_evaluate_on_refresh(struct EvaluationContext *eval_ctx,
Depsgraph *graph,
struct Scene *scene);
/* Editors Integration -------------------------- */
/* Mechanism to allow editors to be informed of depsgraph updates,
* to do their own updates based on changes.
*/
typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id);
typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain,
struct Scene *scene,
int updated);
/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
DEG_EditorUpdateSceneCb scene_func);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __DEG_DEPSGRAPH_H__ */

@ -0,0 +1,117 @@
/*
* ***** 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): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*
* Public API for Depsgraph
*/
#ifndef __DEG_DEPSGRAPH_BUILD_H__
#define __DEG_DEPSGRAPH_BUILD_H__
/* ************************************************* */
/* Dependency Graph */
struct Depsgraph;
/* ------------------------------------------------ */
struct Main;
struct Scene;
struct PointerRNA;
struct PropertyRNA;
#ifdef __cplusplus
extern "C" {
#endif
/* Graph Building -------------------------------- */
/* Build depsgraph for the given scene, and dump results in given graph container */
void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene);
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
/* Tag all relations in the database for update.*/
void DEG_relations_tag_update(struct Main *bmain);
/* Create new graph if didn't exist yet,
* or update relations if graph was tagged for update.
*/
void DEG_scene_relations_update(struct Main *bmain, struct Scene *scene);
/* Rebuild dependency graph only for a given scene. */
void DEG_scene_relations_rebuild(struct Main *bmain,
struct Scene *scene);
/* Delete scene graph. */
void DEG_scene_graph_free(struct Scene *scene);
/* Add Dependencies ----------------------------- */
/* Handle for components to define their dependencies from callbacks.
* This is generated by the depsgraph and passed to dependency callbacks
* as a symbolic reference to the current DepsNode.
* All relations will be defined in reference to that node.
*/
struct DepsNodeHandle;
struct Object;
typedef enum eDepsSceneComponentType {
DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */
} eDepsSceneComponentType;
typedef enum eDepsObjectComponentType {
DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */
DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */
/* Evaluation-Related Outer Types (with Subdata) */
DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */
DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */
DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
DEG_OB_COMP_SHADING, /* Material Shading Component */
} eDepsObjectComponentType;
void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
/* TODO(sergey): Remove once all geometry update is granular. */
void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
/* ************************************************ */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __DEG_DEPSGRAPH_BUILD_H__ */

@ -0,0 +1,107 @@
/*
* ***** 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) 2014 Blender Foundation.
* All rights reserved.
*
* Original Author: Lukas Toenne
* Contributor(s): None Yet
*
* ***** END GPL LICENSE BLOCK *****
*
* Public API for Querying and Filtering Depsgraph
*/
#ifndef __DEG_DEPSGRAPH_DEBUG_H__
#define __DEG_DEPSGRAPH_DEBUG_H__
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
struct DepsgraphSettings;
struct GHash;
struct ID;
struct Depsgraph;
struct DepsNode;
struct DepsRelation;
/* ************************************************ */
/* Statistics */
typedef struct DepsgraphStatsTimes {
float duration_last;
} DepsgraphStatsTimes;
typedef struct DepsgraphStatsComponent {
struct DepsgraphStatsComponent *next, *prev;
char name[64];
DepsgraphStatsTimes times;
} DepsgraphStatsComponent;
typedef struct DepsgraphStatsID {
struct ID *id;
DepsgraphStatsTimes times;
ListBase components;
} DepsgraphStatsID;
typedef struct DepsgraphStats {
struct GHash *id_stats;
} DepsgraphStats;
struct DepsgraphStats *DEG_stats(void);
void DEG_stats_verify(void);
struct DepsgraphStatsID *DEG_stats_id(struct ID *id);
/* ------------------------------------------------ */
void DEG_stats_simple(const struct Depsgraph *graph,
size_t *r_outer,
size_t *r_operations,
size_t *r_relations);
/* ************************************************ */
/* Diagram-Based Graph Debugging */
void DEG_debug_graphviz(const struct Depsgraph *graph, FILE *stream, const char *label, bool show_eval);
/* ************************************************ */
/* Compare two dependency graphs. */
bool DEG_debug_compare(const struct Depsgraph *graph1,
const struct Depsgraph *graph2);
/* Check that dependnecies in the graph are really up to date. */
bool DEG_debug_scene_relations_validate(struct Main *bmain,
struct Scene *scene);
/* Perform consistency check on the graph. */
bool DEG_debug_consistency_check(struct Depsgraph *graph);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __DEG_DEPSGRAPH_DEBUG_H__ */

@ -0,0 +1,191 @@
/*
* ***** 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 *****
*
* Public API for Querying and Filtering Depsgraph
*/
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
struct ListBase;
struct ID;
struct Depsgraph;
struct DepsNode;
struct DepsRelation;
#ifdef __cplusplus
extern "C" {
#endif
/* ************************************************ */
/* Type Defines */
/* FilterPredicate Callback
*
* Defines a callback function which can be supplied to check whether a
* node is relevant or not.
*
* < graph: Depsgraph that we're traversing
* < node: The node to check
* < userdata: FilterPredicate state data (as needed)
* > returns: True if node is relevant
*/
typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata);
/* Node Operation
*
* Performs some action on the given node, provided that the node was
* deemed to be relevant to operate on.
*
* < graph: Depsgraph that we're traversing
* < node: The node to perform operation on/with
* < userdata: Node Operation's state data (as needed)
* > returns: True if traversal should be aborted at this point
*/
typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata);
/* ************************************************ */
/* Low-Level Filtering API */
/* Create a filtered copy of the given graph which contains only the
* nodes which fulfill the criteria specified using the FilterPredicate
* passed in.
*
* < graph: The graph to be copied and filtered
* < filter: FilterPredicate used to check which nodes should be included
* (If null, full graph is copied as-is)
* < userdata: State data for filter (as necessary)
*
* > returns: a full copy of all the relevant nodes - the matching subgraph
*/
// XXX: is there any need for extra settings/options for how the filtering goes?
Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata);
/* Traverse nodes in graph which are deemed relevant,
* performing the provided operation on the nodes.
*
* < graph: The graph to perform operations on
* < filter: FilterPredicate used to check which nodes should be included
* (If null, all nodes are considered valid targets)
* < filter_data: Custom state data for FilterPredicate
* (Note: This can be the same as op_data, where appropriate)
* < op: NodeOperation to perform on each node
* (If null, no graph traversal is performed for efficiency)
* < op_data: Custom state data for NodeOperation
* (Note: This can be the same as filter_data, where appropriate)
*/
void DEG_graph_traverse(const struct Depsgraph *graph,
DEG_FilterPredicate *filter, void *filter_data,
DEG_NodeOperation *op, void *op_data);
/* ************************************************ */
/* Node-Based Operations */
// XXX: do we want to be able to attach conditional requirements here?
/* Find an (outer) node matching given conditions
* ! Assumes that there will only be one such node, or that only the first one matters
*
* < graph: a dependency graph which may or may not contain a node matching these requirements
* < query: query conditions for the criteria that the node must satisfy
*/
//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query);
/* Topology Queries (Direct) ---------------------- */
/* Get list of nodes which directly depend on given node
*
* > result: list to write results to
* < node: the node to find the children/dependents of
*/
void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node);
/* Get list of nodes which given node directly depends on
*
* > result: list to write results to
* < node: the node to find the dependencies of
*/
void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node);
/* Topology Queries (Subgraph) -------------------- */
// XXX: given that subgraphs potentially involve many interconnected nodes, we currently
// just spit out a copy of the subgraph which matches. This works well for the cases
// where these are used - mostly for efficient updating of subsets of the nodes.
// XXX: allow supplying a filter predicate to provide further filtering/pruning?
/* Get all descendants of a node
*
* That is, get the subgraph / subset of nodes which are dependent
* on the results of the given node.
*/
Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node);
/* Get all ancestors of a node
*
* That is, get the subgraph / subset of nodes which the given node
* is dependent on in order to be evaluated.
*/
Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node);
/* ************************************************ */
/* Higher-Level Queries */
/* Get ID-blocks which would be affected if specified ID is modified
* < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
*
* > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
* > returns: number of matching ID-blocks
*/
size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
/* Get ID-blocks which are needed to update/evaluate specified ID
* < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
*
* > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
* > returns: number of matching ID-blocks
*/
size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
/* ************************************************ */
/* Check if given ID type was tagged for update. */
bool DEG_id_type_tagged(struct Main *bmain, short idtype);
/* Get additional evaluation flags for the given ID. */
short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __DEG_DEPSGRAPH_QUERY_H__ */

@ -0,0 +1,74 @@
#!/usr/bin/env python
#
# ***** 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.
#
# The Original Code is: all of this file.
#
# Contributor(s): Nathan Letwory, Joshua Leung.
#
# ***** END GPL LICENSE BLOCK *****
Import('env')
sources = env.Glob('intern/*.cc') + env.Glob('util/*.cc')
incs = [
'.',
'./intern',
'./util',
'#/intern/atomic',
'#/intern/guardedalloc',
'../bmesh',
'../blenlib',
'../blenkernel',
'../makesdna',
'../makesrna',
'../modifiers',
'../windowmanager',
]
defs = []
if env['WITH_BF_BOOST']:
incs.append(env['BF_BOOST_INC'])
defs.append('HAVE_BOOST_FUNCTION_BINDINGS')
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
if env['WITH_UNORDERED_MAP_SUPPORT']:
if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
if env['UNORDERED_MAP_NAMESPACE'] == 'std':
defs.append('DEG_STD_UNORDERED_MAP')
elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
defs.append('DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
defs.append('DEG_TR1_UNORDERED_MAP')
else:
print("-- Replacing unordered_map/set with map/set (warning: slower!)")
defs.append('DEG_NO_UNORDERED_MAP')
if env['WITH_BF_LEGACY_DEPSGRAPH']:
defs.append('WITH_LEGACY_DEPSGRAPH')
env.BlenderLib(libname='bf_depsgraph', sources=sources,
includes=incs, defines=defs,
libtype=['core', 'player'], priority=[200, 40])

@ -0,0 +1,469 @@
/*
* ***** 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): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*
* Core routines for how the Depsgraph works
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
extern "C" {
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
#include "RNA_access.h"
}
#include "DEG_depsgraph.h"
#include "depsgraph.h" /* own include */
#include "depsnode.h"
#include "depsnode_operation.h"
#include "depsnode_component.h"
#include "depsgraph_intern.h"
static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
Depsgraph::Depsgraph()
: root_node(NULL),
need_update(false),
layers((1 << 20) - 1)
{
BLI_spin_init(&lock);
}
Depsgraph::~Depsgraph()
{
/* Free root node - it won't have been freed yet... */
clear_id_nodes();
clear_subgraph_nodes();
if (this->root_node != NULL) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
}
BLI_spin_end(&lock);
}
/* Query Conditions from RNA ----------------------- */
static bool pointer_to_id_node_criteria(const PointerRNA *ptr,
const PropertyRNA *prop,
ID **id)
{
if (!ptr->type)
return false;
if (!prop) {
if (RNA_struct_is_ID(ptr->type)) {
*id = (ID *)ptr->data;
return true;
}
}
return false;
}
static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
const PropertyRNA *prop,
ID **id,
eDepsNode_Type *type,
string *subdata)
{
if (!ptr->type)
return false;
/* Set default values for returns. */
*id = (ID *)ptr->id.data; /* For obvious reasons... */
*subdata = ""; /* Default to no subdata (e.g. bone) name
* lookup in most cases. */
/* Handling of commonly known scenarios... */
if (ptr->type == &RNA_PoseBone) {
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
/* Bone - generally, we just want the bone component... */
*type = DEPSNODE_TYPE_BONE;
*subdata = pchan->name;
return true;
}
else if (ptr->type == &RNA_Bone) {
Bone *bone = (Bone *)ptr->data;
/* armature-level bone, but it ends up going to bone component anyway */
// TODO: the ID in thise case will end up being bArmature, not Object as needed!
*type = DEPSNODE_TYPE_BONE;
*subdata = bone->name;
//*id = ...
return true;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
Object *ob = (Object *)ptr->id.data;
bConstraint *con = (bConstraint *)ptr->data;
/* object or bone? */
if (BLI_findindex(&ob->constraints, con) != -1) {
/* object transform */
// XXX: for now, we can't address the specific constraint or the constraint stack...
*type = DEPSNODE_TYPE_TRANSFORM;
return true;
}
else if (ob->pose) {
bPoseChannel *pchan;
for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (BLI_findindex(&pchan->constraints, con) != -1) {
/* bone transforms */
*type = DEPSNODE_TYPE_BONE;
*subdata = pchan->name;
return true;
}
}
}
}
else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
//ModifierData *md = (ModifierData *)ptr->data;
/* Modifier */
/* NOTE: subdata is not the same as "operation name",
* so although we have unique ops for modifiers,
* we can't lump them together
*/
*type = DEPSNODE_TYPE_BONE;
//*subdata = md->name;
return true;
}
else if (ptr->type == &RNA_Object) {
//Object *ob = (Object *)ptr->data;
/* Transforms props? */
if (prop) {
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
if (strstr(prop_identifier, "location") ||
strstr(prop_identifier, "rotation") ||
strstr(prop_identifier, "scale"))
{
*type = DEPSNODE_TYPE_TRANSFORM;
return true;
}
}
// ...
}
else if (ptr->type == &RNA_ShapeKey) {
Key *key = (Key *)ptr->id.data;
/* ShapeKeys are currently handled as geometry on the geometry that owns it */
*id = key->from; // XXX
*type = DEPSNODE_TYPE_PARAMETERS;
return true;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
Sequence *seq = (Sequence *)ptr->data;
/* Sequencer strip */
*type = DEPSNODE_TYPE_SEQUENCER;
*subdata = seq->name; // xxx?
return true;
}
if (prop) {
/* All unknown data effectively falls under "parameter evaluation" */
*type = DEPSNODE_TYPE_PARAMETERS;
return true;
}
return false;
}
/* Convenience wrapper to find node given just pointer + property. */
DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
const PropertyRNA *prop) const
{
ID *id;
eDepsNode_Type type;
string name;
/* Get querying conditions. */
if (pointer_to_id_node_criteria(ptr, prop, &id)) {
return find_id_node(id);
}
else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
IDDepsNode *id_node = find_id_node(id);
if (id_node)
return id_node->find_component(type, name);
}
return NULL;
}
/* Node Management ---------------------------- */
RootDepsNode *Depsgraph::add_root_node()
{
if (!root_node) {
DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ROOT);
root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
}
return root_node;
}
TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
{
/* Search for one attached to a particular ID? */
if (id) {
/* Check if it was added as a component
* (as may be done for subgraphs needing timeoffset).
*/
IDDepsNode *id_node = find_id_node(id);
if (id_node) {
// XXX: review this
// return id_node->find_component(DEPSNODE_TYPE_TIMESOURCE);
}
BLI_assert(!"Not implemented yet");
}
else {
/* Use "official" timesource. */
return root_node->time_source;
}
return NULL;
}
SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
{
DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
SubgraphDepsNode *subgraph_node =
(SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
/* Add to subnodes list. */
this->subgraphs.insert(subgraph_node);
/* if there's an ID associated, add to ID-nodes lookup too */
if (id) {
#if 0
/* XXX subgraph node is NOT a true IDDepsNode - what is this supposed to do? */
// TODO: what to do if subgraph's ID has already been added?
BLI_assert(!graph->find_id_node(id));
graph->id_hash[id] = this;
#endif
}
return subgraph_node;
}
void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
{
subgraphs.erase(subgraph_node);
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
void Depsgraph::clear_subgraph_nodes()
{
for (Subgraphs::iterator it = subgraphs.begin();
it != subgraphs.end();
++it)
{
SubgraphDepsNode *subgraph_node = *it;
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
subgraphs.clear();
}
IDDepsNode *Depsgraph::find_id_node(const ID *id) const
{
IDNodeMap::const_iterator it = this->id_hash.find(id);
return it != this->id_hash.end() ? it->second : NULL;
}
IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
{
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", name);
id->flag |= LIB_DOIT;
/* register */
this->id_hash[id] = id_node;
}
return id_node;
}
void Depsgraph::remove_id_node(const ID *id)
{
IDDepsNode *id_node = find_id_node(id);
if (id_node) {
/* unregister */
this->id_hash.erase(id);
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
}
void Depsgraph::clear_id_nodes()
{
for (IDNodeMap::const_iterator it = id_hash.begin();
it != id_hash.end();
++it)
{
IDDepsNode *id_node = it->second;
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
id_hash.clear();
}
/* Add new relationship between two nodes. */
DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
eDepsRelation_Type type,
const char *description)
{
/* Create new relation, and add it to the graph. */
DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
return rel;
}
/* Add new relation between two nodes */
DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
eDepsRelation_Type type,
const char *description)
{
/* Create new relation, and add it to the graph. */
DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
return rel;
}
/* ************************ */
/* Relationships Management */
DepsRelation::DepsRelation(DepsNode *from,
DepsNode *to,
eDepsRelation_Type type,
const char *description)
: from(from),
to(to),
name(description),
type(type),
flag(0)
{
#ifndef NDEBUG
/*
for (OperationDepsNode::Relations::const_iterator it = from->outlinks.begin();
it != from->outlinks.end();
++it)
{
DepsRelation *rel = *it;
if (rel->from == from &&
rel->to == to &&
rel->type == type &&
rel->name == description)
{
BLI_assert(!"Duplicated relation, should not happen!");
}
}
*/
#endif
/* Hook it up to the nodes which use it. */
from->outlinks.insert(this);
to->inlinks.insert(this);
}
DepsRelation::~DepsRelation()
{
/* Sanity check. */
BLI_assert(this->from && this->to);
/* Remove it from the nodes that use it. */
this->from->outlinks.erase(this);
this->to->inlinks.erase(this);
}
/* Low level tagging -------------------------------------- */
/* Tag a specific node as needing updates. */
void Depsgraph::add_entry_tag(OperationDepsNode *node)
{
/* Sanity check. */
if (!node)
return;
/* Add to graph-level set of directly modified nodes to start searching from.
* NOTE: this is necessary since we have several thousand nodes to play with...
*/
this->entry_tags.insert(node);
}
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
clear_subgraph_nodes();
id_hash.clear();
if (this->root_node) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
root_node = NULL;
}
}
/* **************** */
/* Public Graph API */
/* Initialize a new Depsgraph */
Depsgraph *DEG_graph_new()
{
return OBJECT_GUARDED_NEW(Depsgraph);
}
/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
OBJECT_GUARDED_DELETE(graph, Depsgraph);
}
/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
DEG_EditorUpdateSceneCb scene_func)
{
deg_editor_update_id_cb = id_func;
deg_editor_update_scene_cb = scene_func;
}
void deg_editors_id_update(Main *bmain, ID *id)
{
if (deg_editor_update_id_cb != NULL) {
deg_editor_update_id_cb(bmain, id);
}
}
void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
{
if (deg_editor_update_scene_cb != NULL) {
deg_editor_update_scene_cb(bmain, scene, updated);
}
}

@ -0,0 +1,220 @@
/*
* ***** 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): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*
* Datatypes for internal use in the Depsgraph
*
* All of these datatypes are only really used within the "core" depsgraph.
* In particular, node types declared here form the structure of operations
* in the graph.
*/
#ifndef __DEPSGRAPH_H__
#define __DEPSGRAPH_H__
#include "BLI_threads.h" /* for SpinLock */
#include "depsgraph_types.h"
#include "depsgraph_util_map.h"
#include "depsgraph_util_set.h"
struct PointerRNA;
struct PropertyRNA;
struct DepsNode;
struct RootDepsNode;
struct TimeSourceDepsNode;
struct IDDepsNode;
struct SubgraphDepsNode;
struct ComponentDepsNode;
struct OperationDepsNode;
/* *************************** */
/* Relationships Between Nodes */
/* Settings/Tags on Relationship */
typedef enum eDepsRelation_Flag {
/* "touched" tag is used when filtering, to know which to collect */
DEPSREL_FLAG_TEMP_TAG = (1 << 0),
/* "cyclic" link - when detecting cycles, this relationship was the one
* which triggers a cyclic relationship to exist in the graph
*/
DEPSREL_FLAG_CYCLIC = (1 << 1),
} eDepsRelation_Flag;
/* B depends on A (A -> B) */
struct DepsRelation {
/* the nodes in the relationship (since this is shared between the nodes) */
DepsNode *from; /* A */
DepsNode *to; /* B */
/* relationship attributes */
const char* name; /* label for debugging */
eDepsRelation_Type type; /* type */
int flag; /* (eDepsRelation_Flag) */
DepsRelation(DepsNode *from,
DepsNode *to,
eDepsRelation_Type type,
const char *description);
~DepsRelation();
};
/* ********* */
/* Depsgraph */
/* Dependency Graph object */
struct Depsgraph {
typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
typedef unordered_set<SubgraphDepsNode *> Subgraphs;
typedef unordered_set<OperationDepsNode *> EntryTags;
typedef vector<OperationDepsNode *> OperationNodes;
Depsgraph();
~Depsgraph();
/**
* Find node which matches the specified description.
*
* \param id: ID block that is associated with this
* \param subdata: identifier used for sub-ID data (e.g. bone)
* \param type: type of node we're dealing with
* \param name: custom identifier assigned to node
*
* \return A node matching the required characteristics if it exists
* or NULL if no such node exists in the graph.
*/
DepsNode *find_node(const ID *id,
eDepsNode_Type type,
const string &subdata,
const string &name);
/**
* Convenience wrapper to find node given just pointer + property.
*
* \param ptr: pointer to the data that node will represent
* \param prop: optional property affected - providing this effectively results in inner nodes being returned
*
* \return A node matching the required characteristics if it exists
* or NULL if no such node exists in the graph
*/
DepsNode *find_node_from_pointer(const PointerRNA *ptr, const PropertyRNA *prop) const;
RootDepsNode *add_root_node();
TimeSourceDepsNode *find_time_source(const ID *id = NULL) const;
SubgraphDepsNode *add_subgraph_node(const ID *id);
void remove_subgraph_node(SubgraphDepsNode *subgraph_node);
void clear_subgraph_nodes();
IDDepsNode *find_id_node(const ID *id) const;
IDDepsNode *add_id_node(ID *id, const string &name = "");
void remove_id_node(const ID *id);
void clear_id_nodes();
/* Add new relationship between two nodes. */
DepsRelation *add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
eDepsRelation_Type type,
const char *description);
DepsRelation *add_new_relation(DepsNode *from,
DepsNode *to,
eDepsRelation_Type type,
const char *description);
/* Tag a specific node as needing updates. */
void add_entry_tag(OperationDepsNode *node);
/* Clear storage used by all nodes. */
void clear_all_nodes();
/* Core Graph Functionality ........... */
/* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
* (for quick lookups). */
IDNodeMap id_hash;
/* "root" node - the one where all evaluation enters from. */
RootDepsNode *root_node;
/* Subgraphs referenced in tree. */
Subgraphs subgraphs;
/* Indicates whether relations needs to be updated. */
bool need_update;
/* Quick-Access Temp Data ............. */
/* Nodes which have been tagged as "directly modified". */
EntryTags entry_tags;
/* Convenience Data ................... */
/* XXX: should be collected after building (if actually needed?) */
/* All operation nodes, sorted in order of single-thread traversal order. */
OperationNodes operations;
/* Spin lock for threading-critical operations.
* Mainly used by graph evaluation.
*/
SpinLock lock;
/* Layers Visibility .................. */
/* Visible layers bitfield, used for skipping invisible objects updates. */
int layers;
// XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
};
/**
* Helper macros for interating over set of relationship links
* incident on each node.
*
* \note it is safe to perform removal operations here...
*
* relations_set[in]: (DepsNode::Relations) set of relationships (in/out links)
* relation[out]: (DepsRelation *) identifier where DepsRelation that we're
* currently accessing comes up
*/
#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \
{ \
OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \
while (__rel_iter != relations_set_.end()) { \
DepsRelation *relation_ = *__rel_iter; \
++__rel_iter; \
/* ... code for iterator body can be written here ... */
#define DEPSNODE_RELATIONS_ITER_END \
} \
} ((void)0)
#endif /* __DEPSGRAPH_H__ */

@ -0,0 +1,365 @@
/*
* ***** 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): Based on original depsgraph.c code - Blender Foundation (2005-2013)
*
* ***** END GPL LICENSE BLOCK *****
*
* Methods for constructing depsgraph
*/
#include <stack>
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_blenlib.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_group.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
#include "BKE_sound.h"
#include "BKE_texture.h"
#include "BKE_tracking.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
#include "RNA_access.h"
#include "RNA_types.h"
} /* extern "C" */
#include "depsnode.h"
#include "depsnode_component.h"
#include "depsgraph_debug.h"
#include "depsnode_operation.h"
#include "depsgraph_types.h"
#include "depsgraph_build.h"
#include "depsgraph_intern.h"
#include "depsgraph_util_cycle.h"
#include "depsgraph_util_transitive.h"
/* ****************** */
/* External Build API */
static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component)
{
switch (component) {
case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER;
}
return DEPSNODE_TYPE_UNDEFINED;
}
static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component)
{
switch (component) {
case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY;
case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM;
case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY;
case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE;
case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE;
case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES;
case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING;
}
return DEPSNODE_TYPE_UNDEFINED;
}
void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description)
{
eDepsNode_Type type = deg_build_scene_component_type(component);
ComponentKey comp_key(&scene->id, type);
handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
}
void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description)
{
eDepsNode_Type type = deg_build_object_component_type(component);
ComponentKey comp_key(&ob->id, type);
handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
}
void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description)
{
eDepsNode_Type type = deg_build_object_component_type(component);
ComponentKey comp_key(&ob->id, type, bone_name);
// XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now
handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
}
void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
{
if (graph == NULL) {
BLI_assert(!"Graph should always be valid");
return;
}
IDDepsNode *id_node = graph->find_id_node(id);
if (id_node == NULL) {
BLI_assert(!"ID should always be valid");
return;
}
id_node->eval_flags |= flag;
}
/* ********************** */
/* Utilities for Builders */
/* Get unique identifier for FCurves and Drivers */
string deg_fcurve_id_name(const FCurve *fcu)
{
char index_buf[32];
sprintf(index_buf, "[%d]", fcu->array_index);
return string(fcu->rna_path) + index_buf;
}
static void deg_graph_build_finalize(Depsgraph *graph)
{
std::stack<OperationDepsNode*> stack;
for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
it_op != graph->operations.end();
++it_op)
{
OperationDepsNode *node = *it_op;
node->done = 0;
node->num_links_pending = 0;
for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
it_rel != node->inlinks.end();
++it_rel)
{
DepsRelation *rel = *it_rel;
if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
(rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
++node->num_links_pending;
}
}
if (node->num_links_pending == 0) {
stack.push(node);
}
IDDepsNode *id_node = node->owner->owner;
id_node->id->flag |= LIB_DOIT;
}
while (!stack.empty()) {
OperationDepsNode *node = stack.top();
if (node->done == 0 && node->outlinks.size() != 0) {
for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
it_rel != node->outlinks.end();
++it_rel)
{
DepsRelation *rel = *it_rel;
if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
BLI_assert(to->num_links_pending > 0);
--to->num_links_pending;
}
if (to->num_links_pending == 0) {
stack.push(to);
}
}
}
node->done = 1;
}
else {
stack.pop();
IDDepsNode *id_node = node->owner->owner;
for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
it_rel != node->outlinks.end();
++it_rel)
{
DepsRelation *rel = *it_rel;
if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
IDDepsNode *id_to = to->owner->owner;
id_node->layers |= id_to->layers;
}
}
/* Re-tag ID for update if it was tagged before the relations
* update tag.
*/
ID *id = id_node->id;
if (id->flag & LIB_ID_RECALC_ALL &&
id->flag & LIB_DOIT)
{
id_node->tag_update(graph);
id->flag &= ~LIB_DOIT;
}
}
}
}
/* ******************** */
/* Graph Building API's */
/* Build depsgraph for the given scene, and dump results in given graph container */
// XXX: assume that this is called from outside, given the current scene as the "main" scene
void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
{
/* 1) Generate all the nodes in the graph first */
DepsgraphNodeBuilder node_builder(bmain, graph);
/* create root node for scene first
* - this way it should be the first in the graph,
* reflecting its role as the entrypoint
*/
node_builder.add_root_node();
node_builder.build_scene(bmain, scene);
/* 2) Hook up relationships between operations - to determine evaluation order */
DepsgraphRelationBuilder relation_builder(graph);
/* hook scene up to the root node as entrypoint to graph */
/* XXX what does this relation actually mean?
* it doesnt add any operations anyway and is not clear what part of the scene is to be connected.
*/
//relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene");
relation_builder.build_scene(bmain, scene);
/* Detect and solve cycles. */
deg_graph_detect_cycles(graph);
/* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */
// TODO: it would be useful to have an option to disable this in cases where it is causing trouble
if (G.debug_value == 799) {
deg_graph_transitive_reduction(graph);
}
/* 4) Flush visibility layer and re-schedule nodes for update. */
deg_graph_build_finalize(graph);
#if 0
if (!DEG_debug_consistency_check(graph)) {
printf("Consistency validation failed, ABORTING!\n");
abort();
}
#endif
}
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
graph->need_update = true;
}
/* Tag all relations for update. */
void DEG_relations_tag_update(Main *bmain)
{
for (Scene *scene = (Scene *)bmain->scene.first;
scene != NULL;
scene = (Scene *)scene->id.next)
{
if (scene->depsgraph != NULL) {
DEG_graph_tag_relations_update(scene->depsgraph);
}
}
}
/* Create new graph if didn't exist yet,
* or update relations if graph was tagged for update.
*/
void DEG_scene_relations_update(Main *bmain, Scene *scene)
{
if (scene->depsgraph == NULL) {
/* Rebuild graph from scratch and exit. */
scene->depsgraph = DEG_graph_new();
DEG_graph_build_from_scene(scene->depsgraph, bmain, scene);
return;
}
Depsgraph *graph = scene->depsgraph;
if (!graph->need_update) {
/* Graph is up to date, nothing to do. */
return;
}
/* Clear all previous nodes and operations. */
graph->clear_all_nodes();
graph->operations.clear();
graph->entry_tags.clear();
/* Build new nodes and relations. */
DEG_graph_build_from_scene(graph, bmain, scene);
graph->need_update = false;
}
/* Rebuild dependency graph only for a given scene. */
void DEG_scene_relations_rebuild(Main *bmain, Scene *scene)
{
if (scene->depsgraph != NULL) {
DEG_graph_tag_relations_update(scene->depsgraph);
}
DEG_scene_relations_update(bmain, scene);
}
void DEG_scene_graph_free(Scene *scene)
{
if (scene->depsgraph) {
DEG_graph_free(scene->depsgraph);
scene->depsgraph = NULL;
}
}

@ -0,0 +1,404 @@
/*
* ***** 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: Lukas Toenne
* Contributor(s): None Yet
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __DEPSGRAPH_BUILD_H__
#define __DEPSGRAPH_BUILD_H__
struct Base;
struct bGPdata;
struct ListBase;
struct GHash;
struct ID;
struct FCurve;
struct Group;
struct Key;
struct Main;
struct Material;
struct MTex;
struct bNodeTree;
struct Object;
struct bPoseChannel;
struct bConstraint;
struct Scene;
struct Tex;
struct World;
struct PropertyRNA;
struct Depsgraph;
struct DepsNode;
struct DepsNodeHandle;
struct RootDepsNode;
struct SubgraphDepsNode;
struct IDDepsNode;
struct TimeSourceDepsNode;
struct ComponentDepsNode;
struct OperationDepsNode;
struct RootPChanMap;
struct DepsgraphNodeBuilder {
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
~DepsgraphNodeBuilder();
RootDepsNode *add_root_node();
IDDepsNode *add_id_node(ID *id);
TimeSourceDepsNode *add_time_source(ID *id);
ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = "");
OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype,
DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype,
DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype,
DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "")
{
return add_operation_node(id, comp_type, "", optype, op, opcode, description);
}
bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name,
eDepsOperation_Code opcode, const string &description = "");
OperationDepsNode *find_operation_node(ID *id,
eDepsNode_Type comp_type,
const string &comp_name,
eDepsOperation_Code opcode,
const string &description = "");
OperationDepsNode *find_operation_node(ID *id,
eDepsNode_Type comp_type,
eDepsOperation_Code opcode,
const string &description = "")
{
return find_operation_node(id, comp_type, "", opcode, description);
}
void build_scene(Main *bmain, Scene *scene);
SubgraphDepsNode *build_subgraph(Group *group);
void build_group(Scene *scene, Base *base, Group *group);
void build_object(Scene *scene, Base *base, Object *ob);
void build_object_transform(Scene *scene, Object *ob);
void build_object_constraints(Scene *scene, Object *ob);
void build_pose_constraints(Object *ob, bPoseChannel *pchan);
void build_rigidbody(Scene *scene);
void build_particles(Object *ob);
void build_animdata(ID *id);
OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
void build_rig(Scene *scene, Object *ob);
void build_proxy_rig(Object *ob);
void build_shapekeys(Key *key);
void build_obdata_geom(Scene *scene, Object *ob);
void build_camera(Object *ob);
void build_lamp(Object *ob);
void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
void build_material(DepsNode *owner_node, Material *ma);
void build_texture(DepsNode *owner_node, Tex *tex);
void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
void build_world(World *world);
void build_compositor(Scene *scene);
void build_gpencil(bGPdata *gpd);
private:
Main *m_bmain;
Depsgraph *m_graph;
};
struct RootKey
{
RootKey() {}
};
struct TimeSourceKey
{
TimeSourceKey() : id(NULL) {}
TimeSourceKey(ID *id) : id(id) {}
string identifier() const
{
return string("TimeSourceKey");
}
ID *id;
};
struct ComponentKey
{
ComponentKey() :
id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("")
{}
ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") :
id(id), type(type), name(name)
{}
string identifier() const
{
const char *idname = (id) ? id->name : "<None>";
char typebuf[5];
sprintf(typebuf, "%d", type);
return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
}
ID *id;
eDepsNode_Type type;
string name;
};
struct OperationKey
{
OperationKey() :
id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("")
{}
OperationKey(ID *id, eDepsNode_Type component_type, const string &name) :
id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name)
{}
OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) :
id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name)
{}
OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) :
id(id), component_type(component_type), component_name(""), opcode(opcode), name("")
{}
OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) :
id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("")
{}
OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) :
id(id), component_type(component_type), component_name(""), opcode(opcode), name(name)
{}
OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) :
id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name)
{}
string identifier() const
{
char typebuf[5];
sprintf(typebuf, "%d", component_type);
return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
}
ID *id;
eDepsNode_Type component_type;
string component_name;
eDepsOperation_Code opcode;
string name;
};
struct RNAPathKey
{
// Note: see depsgraph_build.cpp for implementation
RNAPathKey(ID *id, const string &path);
RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) :
id(id), ptr(ptr), prop(prop)
{}
string identifier() const
{
const char *id_name = (id) ? id->name : "<No ID>";
const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>";
return string("RnaPathKey(") + "id: " + id_name + ", prop: " + prop_name + "')";
}
ID *id;
PointerRNA ptr;
PropertyRNA *prop;
};
struct DepsgraphRelationBuilder
{
DepsgraphRelationBuilder(Depsgraph *graph);
template <typename KeyFrom, typename KeyTo>
void add_relation(const KeyFrom &key_from, const KeyTo &key_to,
eDepsRelation_Type type, const char *description);
template <typename KeyTo>
void add_relation(const TimeSourceKey &key_from, const KeyTo &key_to,
eDepsRelation_Type type, const char *description);
template <typename KeyType>
void add_node_handle_relation(const KeyType &key_from, const DepsNodeHandle *handle,
eDepsRelation_Type type, const char *description);
void build_scene(Main *bmain, Scene *scene);
void build_group(Main *bmain, Scene *scene, Object *object, Group *group);
void build_object(Main *bmain, Scene *scene, Object *ob);
void build_object_parent(Object *ob);
void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
ListBase *constraints, RootPChanMap *root_map);
void build_animdata(ID *id);
void build_driver(ID *id, FCurve *fcurve);
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
void build_rig(Scene *scene, Object *ob);
void build_proxy_rig(Object *ob);
void build_shapekeys(ID *obdata, Key *key);
void build_obdata_geom(Main *bmain, Scene *scene, Object *ob);
void build_camera(Object *ob);
void build_lamp(Object *ob);
void build_nodetree(ID *owner, bNodeTree *ntree);
void build_material(ID *owner, Material *ma);
void build_texture(ID *owner, Tex *tex);
void build_texture_stack(ID *owner, MTex **texture_stack);
void build_compositor(Scene *scene);
void build_gpencil(ID *owner, bGPdata *gpd);
protected:
RootDepsNode *find_node(const RootKey &key) const;
TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
ComponentDepsNode *find_node(const ComponentKey &key) const;
OperationDepsNode *find_node(const OperationKey &key) const;
DepsNode *find_node(const RNAPathKey &key) const;
OperationDepsNode *has_node(const OperationKey &key) const;
void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description);
void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to,
eDepsRelation_Type type, const char *description);
template <typename KeyType>
DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = "");
bool needs_animdata_node(ID *id);
private:
Depsgraph *m_graph;
};
struct DepsNodeHandle
{
DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") :
builder(builder),
node(node),
default_name(default_name)
{
BLI_assert(node != NULL);
}
DepsgraphRelationBuilder *builder;
OperationDepsNode *node;
const string &default_name;
};
/* Utilities for Builders ----------------------------------------------------- */
/* Get unique identifier for FCurves and Drivers */
string deg_fcurve_id_name(const FCurve *fcu);
template <typename KeyFrom, typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
const KeyTo &key_to,
eDepsRelation_Type type,
const char *description)
{
DepsNode *node_from = find_node(key_from);
DepsNode *node_to = find_node(key_to);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
if (op_from && op_to) {
add_operation_relation(op_from, op_to, type, description);
}
else {
if (!op_from) {
/* XXX TODO handle as error or report if needed */
fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n",
type, description, key_from.identifier().c_str());
}
else {
fprintf(stderr, "add_relation(%d, %s) - Failed, but op_from (%s) was ok\n",
type, description, key_from.identifier().c_str());
}
if (!op_to) {
/* XXX TODO handle as error or report if needed */
fprintf(stderr, "add_relation(%d, %s) - Could not find op_to (%s)\n",
type, description, key_to.identifier().c_str());
}
else {
fprintf(stderr, "add_relation(%d, %s) - Failed, but op_to (%s) was ok\n",
type, description, key_to.identifier().c_str());
}
}
}
template <typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
const KeyTo &key_to,
eDepsRelation_Type type,
const char *description)
{
(void)type; /* Ignored in release builds. */
BLI_assert(type == DEPSREL_TYPE_TIME);
TimeSourceDepsNode *time_from = find_node(key_from);
DepsNode *node_to = find_node(key_to);
OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
if (time_from && op_to) {
add_time_relation(time_from, op_to, description);
}
else {
}
}
template <typename KeyType>
void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
const DepsNodeHandle *handle,
eDepsRelation_Type type,
const char *description)
{
DepsNode *node_from = find_node(key_from);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
OperationDepsNode *op_to = handle->node->get_entry_operation();
if (op_from && op_to) {
add_operation_relation(op_from, op_to, type, description);
}
else {
if (!op_from) {
/* XXX TODO handle as error or report if needed */
}
if (!op_to) {
/* XXX TODO handle as error or report if needed */
}
}
}
template <typename KeyType>
DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key,
const string &default_name)
{
return DepsNodeHandle(this, find_node(key), default_name);
}
#endif /* __DEPSGRAPH_BUILD_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,83 @@
/*
* ***** 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 *****
*/
#ifndef __DEPSGRAPH_DEBUG_H__
#define __DEPSGRAPH_DEBUG_H__
#include "depsgraph_types.h"
extern "C" {
#include "BKE_global.h"
}
struct DepsgraphStats;
struct DepsgraphStatsID;
struct DepsgraphStatsComponent;
struct DepsgraphSettings;
struct EvaluationContext;
struct OperationDepsNode;
struct Depsgraph;
struct DepsgraphDebug {
static DepsgraphStats *stats;
static void stats_init();
static void stats_free();
static void verify_stats();
static void reset_stats();
static void eval_begin(const EvaluationContext *eval_ctx);
static void eval_end(const EvaluationContext *eval_ctx);
static void eval_step(const EvaluationContext *eval_ctx,
const char *message);
static void task_started(Depsgraph *graph, const OperationDepsNode *node);
static void task_completed(Depsgraph *graph,
const OperationDepsNode *node,
double time);
static DepsgraphStatsID *get_id_stats(ID *id, bool create);
static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats,
const string &name,
bool create);
static DepsgraphStatsComponent *get_component_stats(ID *id,
const string &name,
bool create)
{
return get_component_stats(get_id_stats(id, create), name, create);
}
};
#define DEG_DEBUG_PRINTF(...) \
{ \
if (G.debug & G_DEBUG_DEPSGRAPH) { \
fprintf(stderr, __VA_ARGS__); \
} \
} \
#endif /* __DEPSGRAPH_DEBUG_H__ */

@ -0,0 +1,386 @@
/*
* ***** 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 *****
*
* Evaluation engine entrypoints for Depsgraph Engine
*/
#include "MEM_guardedalloc.h"
#include "PIL_time.h"
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_task.h"
#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
} /* extern "C" */
#include "atomic_ops.h"
#include "depsgraph.h"
#include "depsnode.h"
#include "depsnode_component.h"
#include "depsnode_operation.h"
#include "depsgraph_debug.h"
#ifdef WITH_LEGACY_DEPSGRAPH
static bool use_legacy_depsgraph = true;
#endif
bool DEG_depsgraph_use_legacy(void)
{
#ifdef DISABLE_NEW_DEPSGRAPH
return true;
#elif defined(WITH_LEGACY_DEPSGRAPH)
return use_legacy_depsgraph;
#else
BLI_assert(!"Should not be used with new depsgraph");
return false;
#endif
}
void DEG_depsgraph_switch_to_legacy(void)
{
#ifdef WITH_LEGACY_DEPSGRAPH
use_legacy_depsgraph = true;
#else
BLI_assert(!"Should not be used with new depsgraph");
#endif
}
void DEG_depsgraph_switch_to_new(void)
{
#ifdef WITH_LEGACY_DEPSGRAPH
use_legacy_depsgraph = false;
#else
BLI_assert(!"Should not be used with new depsgraph");
#endif
}
/* ****************** */
/* Evaluation Context */
/* Create new evaluation context. */
EvaluationContext *DEG_evaluation_context_new(int mode)
{
EvaluationContext *eval_ctx =
(EvaluationContext *)MEM_callocN(sizeof(EvaluationContext),
"EvaluationContext");
eval_ctx->mode = mode;
return eval_ctx;
}
/**
* Initialize evaluation context.
* Used by the areas which currently overrides the context or doesn't have
* access to a proper one.
*/
void DEG_evaluation_context_init(EvaluationContext *eval_ctx, int mode)
{
eval_ctx->mode = mode;
}
/* Free evaluation context. */
void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
{
MEM_freeN(eval_ctx);
}
/* ********************** */
/* Evaluation Entrypoints */
/* Forward declarations. */
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
const int layers);
struct DepsgraphEvalState {
EvaluationContext *eval_ctx;
Depsgraph *graph;
int layers;
};
static void deg_task_run_func(TaskPool *pool,
void *taskdata,
int UNUSED(threadid))
{
DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
OperationDepsNode *node = (OperationDepsNode *)taskdata;
if (!node->is_noop()) {
/* Get context. */
// TODO: who initialises this? "Init" operations aren't able to initialise it!!!
/* TODO(sergey): Wedon't use component contexts at this moment. */
/* ComponentDepsNode *comp = node->owner; */
BLI_assert(node->owner != NULL);
/* Take note of current time. */
double start_time = PIL_check_seconds_timer();
DepsgraphDebug::task_started(state->graph, node);
/* Should only be the case for NOOPs, which never get to this point. */
BLI_assert(node->evaluate);
/* Perform operation. */
node->evaluate(state->eval_ctx);
/* Note how long this took. */
double end_time = PIL_check_seconds_timer();
DepsgraphDebug::task_completed(state->graph,
node,
end_time - start_time);
}
schedule_children(pool, state->graph, node, state->layers);
}
static void calculate_pending_parents(Depsgraph *graph, int layers)
{
for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
it_op != graph->operations.end();
++it_op)
{
OperationDepsNode *node = *it_op;
IDDepsNode *id_node = node->owner->owner;
node->num_links_pending = 0;
node->scheduled = false;
/* count number of inputs that need updates */
if ((id_node->layers & layers) != 0 &&
(node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
{
for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
it_rel != node->inlinks.end();
++it_rel)
{
DepsRelation *rel = *it_rel;
if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
(rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
{
OperationDepsNode *from = (OperationDepsNode *)rel->from;
IDDepsNode *id_from_node = from->owner->owner;
if ((id_from_node->layers & layers) != 0 &&
(from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
{
++node->num_links_pending;
}
}
}
}
}
}
static void calculate_eval_priority(OperationDepsNode *node)
{
if (node->done) {
return;
}
node->done = 1;
if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
/* XXX standard cost of a node, could be estimated somewhat later on */
const float cost = 1.0f;
/* NOOP nodes have no cost */
node->eval_priority = node->is_noop() ? cost : 0.0f;
for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
it != node->outlinks.end();
++it)
{
DepsRelation *rel = *it;
OperationDepsNode *to = (OperationDepsNode *)rel->to;
BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
calculate_eval_priority(to);
node->eval_priority += to->eval_priority;
}
}
else {
node->eval_priority = 0.0f;
}
}
static void schedule_graph(TaskPool *pool,
Depsgraph *graph,
const int layers)
{
BLI_spin_lock(&graph->lock);
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
IDDepsNode *id_node = node->owner->owner;
if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) &&
node->num_links_pending == 0 &&
(id_node->layers & layers) != 0)
{
BLI_task_pool_push(pool, deg_task_run_func, node, false, TASK_PRIORITY_LOW);
node->scheduled = true;
}
}
BLI_spin_unlock(&graph->lock);
}
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
const int layers)
{
for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
it != node->outlinks.end();
++it)
{
DepsRelation *rel = *it;
OperationDepsNode *child = (OperationDepsNode *)rel->to;
BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
if (child->scheduled) {
/* Happens when having cyclic dependencies. */
continue;
}
IDDepsNode *id_child = child->owner->owner;
if ((id_child->layers & layers) != 0 &&
(child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
{
if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
BLI_assert(child->num_links_pending > 0);
atomic_sub_uint32(&child->num_links_pending, 1);
}
if (child->num_links_pending == 0) {
BLI_spin_lock(&graph->lock);
bool need_schedule = !child->scheduled;
child->scheduled = true;
BLI_spin_unlock(&graph->lock);
if (need_schedule) {
BLI_task_pool_push(pool, deg_task_run_func, child, false, TASK_PRIORITY_LOW);
}
}
}
}
}
/**
* Evaluate all nodes tagged for updating,
* \warning This is usually done as part of main loop, but may also be
* called from frame-change update.
*
* \note Time sources should be all valid!
*/
void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
Depsgraph *graph,
const int layers)
{
/* Generate base evaluation context, upon which all the others are derived. */
// TODO: this needs both main and scene access...
/* Nothing to update, early out. */
if (graph->entry_tags.size() == 0) {
return;
}
/* Set time for the current graph evaluation context. */
TimeSourceDepsNode *time_src = graph->find_time_source();
eval_ctx->ctime = time_src->cfra;
/* XXX could use a separate pool for each eval context */
DepsgraphEvalState state;
state.eval_ctx = eval_ctx;
state.graph = graph;
state.layers = layers;
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
calculate_pending_parents(graph, layers);
/* Clear tags. */
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
node->done = 0;
}
/* Calculate priority for operation nodes. */
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
calculate_eval_priority(node);
}
DepsgraphDebug::eval_begin(eval_ctx);
schedule_graph(task_pool, graph, layers);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
DepsgraphDebug::eval_end(eval_ctx);
/* Clear any uncleared tags - just in case. */
DEG_graph_clear_tags(graph);
}
/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph,
Scene *scene)
{
/* Update time on primary timesource. */
TimeSourceDepsNode *tsrc = graph->find_time_source();
tsrc->cfra = BKE_scene_frame_get(scene);;
DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers);
}
/* Frame-change happened for root scene that graph belongs to. */
void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
Main *bmain,
Depsgraph *graph,
float ctime,
const int layers)
{
/* Update time on primary timesource. */
TimeSourceDepsNode *tsrc = graph->find_time_source();
tsrc->cfra = ctime;
tsrc->tag_update(graph);
DEG_graph_flush_updates(bmain, graph);
/* Perform recalculation updates. */
DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers);
}

@ -0,0 +1,164 @@
/*
* ***** 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 *****
*
* API's for internal use in the Depsgraph
* - Also, defines for "Node Type Info"
*/
#ifndef __DEPSGRAPH_INTERN_H__
#define __DEPSGRAPH_INTERN_H__
#include <cstdlib>
#include "MEM_guardedalloc.h"
#include "depsgraph.h"
#include "depsnode.h"
struct Main;
struct Group;
struct Scene;
/* Graph Building ======================================================== */
/**
* Build depsgraph for the given group, and dump results in given graph container
* This is usually used for building subgraphs for groups to use...
*/
void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group);
/* Build subgraph for group */
DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group);
/* Graph Copying ========================================================= */
/* (Part of the Filtering API) */
/**
* Depsgraph Copying Context (dcc)
*
* Keeps track of node relationships/links/etc. during the copy
* operation so that they can be safely remapped...
*/
typedef struct DepsgraphCopyContext {
struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */
struct GHash *rels_hash; // XXX: same for relationships?
// XXX: filtering criteria...
} DepsgraphCopyContext;
/* Internal Filtering API ---------------------------------------------- */
/* Create filtering context */
// XXX: needs params for conditions?
DepsgraphCopyContext *DEG_filter_init(void);
/* Free filtering context once filtering is done */
void DEG_filter_cleanup(DepsgraphCopyContext *dcc);
/* Data Copy Operations ------------------------------------------------ */
/**
* Make a (deep) copy of provided node and it's little subgraph
* \warning Newly created node is not added to the existing graph
* \param dcc: Context info for helping resolve links
*/
DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src);
/* Node Types Handling ================================================= */
/* "Typeinfo" for Node Types ------------------------------------------- */
/* Typeinfo Struct (nti) */
struct DepsNodeFactory {
virtual eDepsNode_Type type() const = 0;
virtual eDepsNode_Class tclass() const = 0;
virtual const char *tname() const = 0;
virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0;
virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0;
};
template <class NodeType>
struct DepsNodeFactoryImpl : public DepsNodeFactory {
eDepsNode_Type type() const { return NodeType::typeinfo.type; }
eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; }
const char *tname() const { return NodeType::typeinfo.tname; }
DepsNode *create_node(const ID *id, const string &subdata, const string &name) const
{
DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
/* populate base node settings */
node->type = type();
node->tclass = tclass();
if (!name.empty())
/* set name if provided ... */
node->name = name;
else
/* ... otherwise use default type name */
node->name = tname();
node->init(id, subdata);
return node;
}
virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const
{
BLI_assert(copy->type == type());
DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
/* populate base node settings */
node->type = type();
node->tclass = tclass();
// XXX: need to review the name here, as we can't have exact duplicates...
node->name = copy->name;
node->copy(dcc, static_cast<const NodeType *>(copy));
return node;
}
};
/* Typeinfo Management -------------------------------------------------- */
/* Register typeinfo */
void DEG_register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type);
/* Get typeinfo for provided node */
DepsNodeFactory *DEG_node_get_factory(const DepsNode *node);
/* Editors Integration -------------------------------------------------- */
void deg_editors_id_update(struct Main *bmain, struct ID *id);
void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
#endif /* __DEPSGRAPH_INTERN_H__ */

@ -0,0 +1,213 @@
/*
* ***** 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 *****
*
* Implementation of Querying and Filtering API's
*/
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BKE_main.h"
#include "DEG_depsgraph_query.h"
} /* extern "C" */
#include "depsgraph_queue.h"
#include "depsnode.h"
#include "depsnode_operation.h"
#include "depsgraph_intern.h"
/* ************************* */
/* Low-Level Graph Traversal */
#if 0
/* Prepare for graph traversal, by tagging nodes, etc. */
static void DEG_graph_traverse_begin(Depsgraph * /*graph*/)
{
/* go over all nodes, initialising the valence counts */
// XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes...
}
/* Perform a traversal of graph from given starting node (in execution order) */
// TODO: additional flags for controlling the process?
void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node,
DEG_FilterPredicate filter, void *filter_data,
DEG_NodeOperation op, void *operation_data)
{
DepsgraphQueue *q;
/* sanity checks */
if (ELEM(NULL, graph, start_node, op))
return;
/* add node as starting node to be evaluated, with value of 0 */
q = DEG_queue_new();
start_node->num_links_pending = 0;
DEG_queue_push(q, start_node, 0.0f);
/* while we still have nodes in the queue, grab and work on next one */
do {
/* grab item at front of queue */
// XXX: in practice, we may need to wait until one becomes available...
OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q);
/* perform operation on node */
op(graph, node, operation_data);
/* schedule up operations which depend on this */
DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
{
/* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */
// TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one
if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
OperationDepsNode *child_node = (OperationDepsNode *)rel->to;
/* only visit node if the filtering function agrees */
if ((filter == NULL) || filter(graph, child_node, filter_data)) {
/* schedule up node... */
child_node->num_links_pending--;
DEG_queue_push(q, child_node, (float)child_node->num_links_pending);
}
}
}
DEPSNODE_RELATIONS_ITER_END;
} while (DEG_queue_is_empty(q) == false);
/* cleanup */
DEG_queue_free(q);
}
#endif
/* ************************************************************** */
/* Filtering API - Basically, making a copy of the existing graph */
/* Create filtering context */
// TODO: allow passing in a number of criteria?
DepsgraphCopyContext *DEG_filter_init()
{
DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext");
/* init hashes for easy lookups */
dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash");
dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX?
/* store filtering criteria? */
// xxx...
return dcc;
}
/* Cleanup filtering context */
void DEG_filter_cleanup(DepsgraphCopyContext *dcc)
{
/* sanity check */
if (dcc == NULL)
return;
/* free hashes - contents are weren't copied, so are ok... */
BLI_ghash_free(dcc->nodes_hash, NULL, NULL);
BLI_ghash_free(dcc->rels_hash, NULL, NULL);
/* clear filtering criteria */
// ...
/* free dcc itself */
MEM_freeN(dcc);
}
/* -------------------------------------------------- */
/* Create a copy of provided node */
// FIXME: the handling of sub-nodes and links will need to be subject to filtering options...
// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process?
DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src)
{
/* sanity check */
if (src == NULL)
return NULL;
DepsNodeFactory *factory = DEG_get_node_factory(src->type);
BLI_assert(factory != NULL);
DepsNode *dst = factory->copy_node(dcc, src);
/* add this node-pair to the hash... */
BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst);
#if 0 /* XXX TODO */
/* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all
* all others are derived from) that are now corrupt
*/
{
/* relationships to other nodes... */
// FIXME: how to handle links? We may only have partial set of all nodes still?
// XXX: the exact details of how to handle this are really part of the querying API...
// XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways
// (i.e. for resolving and patching over links that exist within subtree...)
dst->inlinks.clear();
dst->outlinks.clear();
/* clear traversal data */
dst->num_links_pending = 0;
dst->lasttime = 0;
}
/* fix links */
// XXX...
#endif
/* return copied node */
return dst;
}
bool DEG_id_type_tagged(Main *bmain, short idtype)
{
return bmain->id_tag_update[((unsigned char *)&idtype)[0]] != 0;
}
short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
{
if (graph == NULL) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
*
* Currently harmless because it's only called for temporary
* objects which are out of the DAG anyway.
*/
return 0;
}
IDDepsNode *id_node = graph->find_id_node(id);
if (id_node == NULL) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
}
return id_node->eval_flags;
}

@ -0,0 +1,173 @@
/*
* ***** 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 *****
*
* Implementation of special queue type for use in Depsgraph traversals
*/
#include <stdlib.h>
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_heap.h"
#include "BLI_ghash.h"
} /* extern "C" */
#include "depsgraph_queue.h"
/* ****************************** */
/* Depsgraph Queue implementation */
/* Data Management ----------------------------------------- */
DepsgraphQueue *DEG_queue_new(void)
{
DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()");
/* init data structures for use here */
q->pending_heap = BLI_heap_new();
q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash");
q->ready_heap = BLI_heap_new();
/* init settings */
q->idx = 0;
q->tot = 0;
/* return queue */
return q;
}
void DEG_queue_free(DepsgraphQueue *q)
{
/* free data structures */
BLI_assert(BLI_heap_size(q->pending_heap) == 0);
BLI_assert(BLI_heap_size(q->ready_heap) == 0);
BLI_assert(BLI_ghash_size(q->pending_hash) == 0);
BLI_heap_free(q->pending_heap, NULL);
BLI_heap_free(q->ready_heap, NULL);
BLI_ghash_free(q->pending_hash, NULL, NULL);
/* free queue itself */
MEM_freeN(q);
}
/* Statistics --------------------------------------------- */
/* Get the number of nodes which are we should visit, but are not able to yet */
size_t DEG_queue_num_pending(DepsgraphQueue *q)
{
return BLI_heap_size(q->pending_heap);
}
/* Get the number of nodes which are now ready to be visited */
size_t DEG_queue_num_ready(DepsgraphQueue *q)
{
return BLI_heap_size(q->ready_heap);
}
/* Get total size of queue */
size_t DEG_queue_size(DepsgraphQueue *q)
{
return DEG_queue_num_pending(q) + DEG_queue_num_ready(q);
}
/* Check if queue has any items in it (still passing through) */
bool DEG_queue_is_empty(DepsgraphQueue *q)
{
return DEG_queue_size(q) == 0;
}
/* Queue Operations --------------------------------------- */
/**
* Add DepsNode to the queue
* \param dnode: ``(DepsNode *)`` node to add to the queue
* Each node is only added once to the queue; Subsequent pushes
* merely update its status (e.g. moving it from "pending" to "ready")
* \param cost: new "num_links_pending" count for node *after* it has encountered
* via an outlink from the node currently being visited
* (i.e. we're one of the dependencies which may now be able to be processed)
*/
void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost)
{
HeapNode *hnode = NULL;
/* Shortcut: Directly add to ready if node isn't waiting on anything now... */
if (cost == 0) {
/* node is now ready to be visited - schedule it up for such */
if (BLI_ghash_haskey(q->pending_hash, dnode)) {
/* remove from pending queue - we're moving it to the scheduling queue */
hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
BLI_heap_remove(q->pending_heap, hnode);
BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL);
}
/* schedule up node using latest count (of ready nodes) */
BLI_heap_insert(q->ready_heap, (float)q->idx, dnode);
q->idx++;
}
else {
/* node is still waiting on some other ancestors,
* so add it to the pending heap in the meantime...
*/
// XXX: is this even necessary now?
if (BLI_ghash_haskey(q->pending_hash, dnode)) {
/* just update cost on pending node */
hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
BLI_heap_remove(q->pending_heap, hnode);
BLI_heap_insert(q->pending_heap, cost, hnode);
}
else {
/* add new node to pending queue, and increase size of overall queue */
hnode = BLI_heap_insert(q->pending_heap, cost, dnode);
q->tot++;
}
}
}
/* Grab a "ready" node from the queue */
void *DEG_queue_pop(DepsgraphQueue *q)
{
/* sanity check: if there are no "ready" nodes,
* start pulling from "pending" to keep things moving,
* but throw a warning so that we know that something's up here...
*/
if (BLI_heap_is_empty(q->ready_heap)) {
// XXX: this should never happen
// XXX: if/when it does happen, we may want instead to just wait until something pops up here...
printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n",
(int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q));
return BLI_heap_popmin(q->pending_heap);
}
else {
/* only grab "ready" nodes */
return BLI_heap_popmin(q->ready_heap);
}
}

@ -0,0 +1,87 @@
/*
* ***** 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 *****
*
* Defines for special queue type for use in Depsgraph traversals
*/
#ifndef __DEPSGRAPH_QUEUE_H__
#define __DEPSGRAPH_QUEUE_H__
struct DepsNode;
struct Heap;
struct GHash;
/* *********************************************** */
/* Dependency Graph Traversal Queue
*
* There are two parts to this:
* a) "Pending" Nodes - This part contains the set of nodes
* which are related to those which have been visited
* previously, but are not yet ready to actually be visited.
* b) "Scheduled" Nodes - These are the nodes whose ancestors
* have all been evaluated already, which means that any
* or all of them can be picked (in practically in order) to
* be visited immediately.
*
* Internally, the queue makes sure that each node in the graph
* only gets added to the queue once. This is because there can
* be multiple inlinks to each node given the way that the relations
* work.
*/
/* Depsgraph Queue Type */
typedef struct DepsgraphQueue {
/* Pending */
struct Heap *pending_heap; /* (valence:int, DepsNode*) */
struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */
/* Ready to be visited - fifo */
struct Heap *ready_heap; /* (idx:int, DepsNode*) */
/* Size/Order counts */
size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */
size_t tot; /* total number of nodes which have passed through queue; mainly for debug */
} DepsgraphQueue;
/* ************************** */
/* Depsgraph Queue Operations */
/* Data management */
DepsgraphQueue *DEG_queue_new(void);
void DEG_queue_free(DepsgraphQueue *q);
/* Statistics */
size_t DEG_queue_num_pending(DepsgraphQueue *q);
size_t DEG_queue_num_ready(DepsgraphQueue *q);
size_t DEG_queue_size(DepsgraphQueue *q);
bool DEG_queue_is_empty(DepsgraphQueue *q);
/* Operations */
void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f);
void *DEG_queue_pop(DepsgraphQueue *q);
#endif /* DEPSGRAPH_QUEUE_H */

@ -0,0 +1,490 @@
/*
* ***** 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 *****
*
* Core routines for how the Depsgraph works
*/
#include <stdio.h>
#include <cstring>
#include <queue>
extern "C" {
#include "BLI_utildefines.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
#define new new_
#include "BKE_screen.h"
#undef new
#include "DEG_depsgraph.h"
} /* extern "C" */
#include "depsgraph_debug.h"
#include "depsnode.h"
#include "depsnode_component.h"
#include "depsnode_operation.h"
#include "depsgraph_intern.h"
/* *********************** */
/* Update Tagging/Flushing */
/* Data-Based Tagging ------------------------------- */
static void lib_id_recalc_tag(Main *bmain, ID *id)
{
id->flag |= LIB_ID_RECALC;
DEG_id_type_tag(bmain, GS(id->name));
}
static void lib_id_recalc_data_tag(Main *bmain, ID *id)
{
id->flag |= LIB_ID_RECALC_DATA;
DEG_id_type_tag(bmain, GS(id->name));
}
static void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
{
if (flag) {
/* This bit of code ensures legacy object->recalc flags
* are still filled in the same way as it was expected
* with the old dependency graph.
*
* This is because some areas like motion paths and likely
* some other physics baking process are doing manual scene
* update on all the frames, trying to minimize number of
* updates.
*
* But this flag will also let us to re-construct entry
* nodes for update after relations update and after layer
* visibility changes.
*/
short idtype = GS(id->name);
if (idtype == ID_OB) {
Object *object = (Object *)id;
object->recalc |= (flag & OB_RECALC_ALL);
}
if (flag & OB_RECALC_OB)
lib_id_recalc_tag(bmain, id);
if (flag & (OB_RECALC_DATA | PSYS_RECALC))
lib_id_recalc_data_tag(bmain, id);
}
else {
lib_id_recalc_tag(bmain, id);
}
}
/* Tag all nodes in ID-block for update.
* This is a crude measure, but is most convenient for old code.
*/
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
{
IDDepsNode *node = graph->find_id_node(id);
lib_id_recalc_tag(bmain, id);
if (node != NULL) {
node->tag_update(graph);
}
}
/* Tag nodes related to a specific piece of data */
void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr)
{
DepsNode *node = graph->find_node_from_pointer(ptr, NULL);
if (node) {
node->tag_update(graph);
}
else {
printf("Missing node in %s\n", __func__);
BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
}
}
/* Tag nodes related to a specific property. */
void DEG_graph_property_tag_update(Depsgraph *graph,
const PointerRNA *ptr,
const PropertyRNA *prop)
{
DepsNode *node = graph->find_node_from_pointer(ptr, prop);
if (node) {
node->tag_update(graph);
}
else {
printf("Missing node in %s\n", __func__);
BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
}
}
/* Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(ID *id, short flag)
{
DEG_id_tag_update_ex(G.main, id, flag);
}
void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
{
if(id == NULL) {
/* Ideally should not happen, but old depsgraph allowed this. */
return;
}
DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag);
lib_id_recalc_tag_flag(bmain, id, flag);
for (Scene *scene = (Scene *)bmain->scene.first;
scene != NULL;
scene = (Scene *)scene->id.next)
{
if (scene->depsgraph) {
Depsgraph *graph = scene->depsgraph;
if (flag == 0) {
/* TODO(sergey): Currently blender is still tagging IDs
* for recalc just using flag=0. This isn't totally correct
* but we'd better deal with such cases and don't fail.
*/
DEG_graph_id_tag_update(bmain, graph, id);
continue;
}
if (flag & OB_RECALC_DATA && GS(id->name) == ID_OB) {
Object *object = (Object*)id;
if (object->data != NULL) {
DEG_graph_id_tag_update(bmain,
graph,
(ID*)object->data);
}
}
if (flag & (OB_RECALC_OB|OB_RECALC_DATA)) {
DEG_graph_id_tag_update(bmain, graph, id);
}
}
}
}
/* Tag given ID type for update. */
void DEG_id_type_tag(Main *bmain, short idtype)
{
if (idtype == ID_NT) {
/* Stupid workaround so parent datablocks of nested nodetree get looped
* over when we loop over tagged datablock types.
*/
DEG_id_type_tag(bmain, ID_MA);
DEG_id_type_tag(bmain, ID_TE);
DEG_id_type_tag(bmain, ID_LA);
DEG_id_type_tag(bmain, ID_WO);
DEG_id_type_tag(bmain, ID_SCE);
}
/* We tag based on first ID type character to avoid
* looping over all ID's in case there are no tags.
*/
bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
}
/* Update Flushing ---------------------------------- */
/* FIFO queue for tagged nodes that need flushing */
/* XXX This may get a dedicated implementation later if needed - lukas */
typedef std::queue<OperationDepsNode*> FlushQueue;
/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
{
/* sanity check */
if (graph == NULL)
return;
/* Nothing to update, early out. */
if (graph->entry_tags.size() == 0) {
return;
}
/* TODO(sergey): With a bit of flag magic we can get rid of this
* extra loop.
*/
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
node->scheduled = false;
}
FlushQueue queue;
/* Starting from the tagged "entry" nodes, flush outwards... */
/* NOTE: Also need to ensure that for each of these, there is a path back to
* root, or else they won't be done.
* NOTE: Count how many nodes we need to handle - entry nodes may be
* component nodes which don't count for this purpose!
*/
for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
it != graph->entry_tags.end();
++it)
{
OperationDepsNode *node = *it;
IDDepsNode *id_node = node->owner->owner;
queue.push(node);
deg_editors_id_update(bmain, id_node->id);
node->scheduled = true;
}
while (!queue.empty()) {
OperationDepsNode *node = queue.front();
queue.pop();
IDDepsNode *id_node = node->owner->owner;
lib_id_recalc_tag(bmain, id_node->id);
/* TODO(sergey): For until we've got proper data nodes in the graph. */
lib_id_recalc_data_tag(bmain, id_node->id);
ID *id = id_node->id;
/* This code is used to preserve those areas which does direct
* object update,
*
* Plus it ensures visibility changes and relations and layers
* visibility update has proper flags to work with.
*/
if (GS(id->name) == ID_OB) {
Object *object = (Object *)id;
ComponentDepsNode *comp_node = node->owner;
if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
object->recalc |= OB_RECALC_TIME;
}
else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
object->recalc |= OB_RECALC_OB;
}
else {
object->recalc |= OB_RECALC_DATA;
}
}
/* Flush to nodes along links... */
for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
it != node->outlinks.end();
++it)
{
DepsRelation *rel = *it;
OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
if (to_node->scheduled == false) {
to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
queue.push(to_node);
to_node->scheduled = true;
deg_editors_id_update(bmain, id_node->id);
}
}
/* TODO(sergey): For until incremental updates are possible
* witin a component at least we tag the whole component
* for update.
*/
for (ComponentDepsNode::OperationMap::iterator it = node->owner->operations.begin();
it != node->owner->operations.end();
++it)
{
OperationDepsNode *op = it->second;
op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
}
}
}
/* Recursively push updates out to all nodes dependent on this,
* until all affected are tagged and/or scheduled up for eval
*/
void DEG_ids_flush_tagged(Main *bmain)
{
for (Scene *scene = (Scene*)bmain->scene.first;
scene != NULL;
scene = (Scene*)scene->id.next)
{
/* TODO(sergey): Only visible scenes? */
if (scene->depsgraph != NULL) {
DEG_graph_flush_updates(bmain, scene->depsgraph);
}
}
}
/* Clear tags from all operation nodes. */
void DEG_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
/* Clear node's "pending update" settings. */
node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
/* Reset so that it can be bumped up again. */
node->num_links_pending = 0;
node->scheduled = false;
}
/* Clear any entry tags which haven't been flushed. */
graph->entry_tags.clear();
}
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
{
Depsgraph *graph = scene->depsgraph;
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
int old_layers = graph->layers;
if (wm != NULL) {
BKE_main_id_flag_listbase(&bmain->scene, LIB_DOIT, true);
graph->layers = 0;
for (wmWindow *win = (wmWindow *)wm->windows.first;
win != NULL;
win = (wmWindow *)win->next)
{
Scene *scene = win->screen->scene;
if (scene->id.flag & LIB_DOIT) {
graph->layers |= BKE_screen_visible_layers(win->screen, scene);
scene->id.flag &= ~LIB_DOIT;
}
}
}
else {
/* All the layers for background render for now. */
graph->layers = (1 << 20) - 1;
}
if (old_layers != graph->layers) {
/* Tag all objects which becomes visible (or which becomes needed for dependencies)
* for recalc.
*
* This is mainly needed on file load only, after that updates of invisible objects
* will be stored in the pending list.
*/
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
IDDepsNode *id_node = node->owner->owner;
ID *id = id_node->id;
if ((id->flag & LIB_ID_RECALC_ALL) != 0 ||
(id_node->layers & scene->lay_updated) == 0)
{
id_node->tag_update(graph);
}
/* A bit of magic: if object->recalc is set it means somebody tagged
* it for update. If corresponding ID recalc flags are zero it means
* graph has been evaluated after that and the recalc was skipped
* because of visibility check.
*/
if (GS(id->name) == ID_OB) {
Object *object = (Object *)id;
if ((id->flag & LIB_ID_RECALC_ALL) == 0 &&
(object->recalc & OB_RECALC_ALL) != 0)
{
id_node->tag_update(graph);
ComponentDepsNode *anim_comp =
id_node->find_component(DEPSNODE_TYPE_ANIMATION);
if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
anim_comp->tag_update(graph);
}
}
}
}
}
scene->lay_updated |= graph->layers;
}
void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
{
for (Scene *scene = (Scene*)bmain->scene.first;
scene != NULL;
scene = (Scene*)scene->id.next)
{
if (scene->depsgraph != NULL) {
DEG_graph_on_visible_update(bmain, scene);
}
}
}
/* Check if something was changed in the database and inform
* editors about this.
*/
void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
{
ListBase *lbarray[MAX_LIBARRAY];
int a;
bool updated = false;
/* Loop over all ID types. */
a = set_listbasepointers(bmain, lbarray);
while (a--) {
ListBase *lb = lbarray[a];
ID *id = (ID*)lb->first;
/* We tag based on first ID type character to avoid
* looping over all ID's in case there are no tags.
*/
if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
updated = true;
break;
}
}
deg_editors_scene_update(bmain, scene, (updated || time));
}
void DEG_ids_clear_recalc(Main *bmain)
{
ListBase *lbarray[MAX_LIBARRAY];
bNodeTree *ntree;
int a;
/* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags
* and id_tags storage from the new dependency graph.
*/
/* Loop over all ID types. */
a = set_listbasepointers(bmain, lbarray);
while (a--) {
ListBase *lb = lbarray[a];
ID *id = (ID *)lb->first;
/* We tag based on first ID type character to avoid
* looping over all ID's in case there are no tags.
*/
if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
for (; id; id = (ID *)id->next) {
id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
/* Some ID's contain semi-datablock nodetree */
ntree = ntreeFromID(id);
if (ntree != NULL) {
ntree->id.flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
}
}
}
}
memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update));
}

@ -0,0 +1,98 @@
/*
* ***** 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 *****
*
* Defines and code for core node types
*/
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "DEG_depsgraph.h"
} /* extern "C" */
#include "depsgraph_intern.h"
#include "depsnode.h"
#include "depsnode_component.h"
#include "depsnode_operation.h"
/* ************ */
/* External API */
/* Global type registry */
/**
* \note For now, this is a hashtable not array, since the core node types
* currently do not have contiguous ID values. Using a hash here gives us
* more flexibility, albeit using more memory and also sacrificing a little
* speed. Later on, when things stabilise we may turn this back to an array
* since there are only just a few node types that an array would cope fine...
*/
static GHash *_depsnode_typeinfo_registry = NULL;
/* Registration ------------------------------------------- */
/* Register node type */
void DEG_register_node_typeinfo(DepsNodeFactory *factory)
{
BLI_assert(factory != NULL);
BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
}
/* Register all node types */
void DEG_register_node_types(void)
{
/* initialise registry */
_depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
/* register node types */
DEG_register_base_depsnodes();
DEG_register_component_depsnodes();
DEG_register_operation_depsnodes();
}
/* Free registry on exit */
void DEG_free_node_types(void)
{
BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL);
}
/* Getters ------------------------------------------------- */
/* Get typeinfo for specified type */
DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type)
{
/* look up type - at worst, it doesn't exist in table yet, and we fail */
return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
}
/* Get typeinfo for provided node */
DepsNodeFactory *DEG_node_get_factory(const DepsNode *node)
{
if (!node)
return NULL;
return DEG_get_node_factory(node->type);
}

@ -0,0 +1,169 @@
/*
* ***** 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 *****
*
* Datatypes for internal use in the Depsgraph
*
* All of these datatypes are only really used within the "core" depsgraph.
* In particular, node types declared here form the structure of operations
* in the graph.
*/
#ifndef __DEPSGRAPH_TYPES_H__
#define __DEPSGRAPH_TYPES_H__
#include "depsgraph_util_function.h"
/* TODO(sergey): Ideally we'll just use char* and statically allocated strings
* to avoid any possible overhead caused by string (re)allocation/formatting.
*/
#include <string>
#include <vector>
using std::string;
using std::vector;
struct bAction;
struct ChannelDriver;
struct ModifierData;
struct PointerRNA;
struct EvaluationContext;
struct FCurve;
/* Evaluation Operation for atomic operation */
// XXX: move this to another header that can be exposed?
typedef function<void(struct EvaluationContext*)> DepsEvalOperationCb;
/* Metatype of Nodes - The general "level" in the graph structure the node serves */
typedef enum eDepsNode_Class {
DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */
DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */
DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */
} eDepsNode_Class;
/* Types of Nodes */
typedef enum eDepsNode_Type {
DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */
DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */
/* Generic Types */
DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */
DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */
DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */
DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */
/* Outer Types */
DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters?
DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */
DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */
DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */
/* Evaluation-Related Outer Types (with Subdata) */
DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */
DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */
DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */
DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */
} eDepsNode_Type;
/* Identifiers for common operations (as an enum) */
typedef enum eDepsOperation_Code {
#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label,
#include "depsnode_opcodes.h"
#undef DEF_DEG_OPCODE
} eDepsOperation_Code;
/* String defines for these opcodes, defined in depsnode_operation.cpp */
extern const char *DEG_OPNAMES[];
/* Type of operation */
typedef enum eDepsOperation_Type {
/* Primary operation types */
DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */
DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */
DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */
/* Additional operation types */
DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX?
DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */
DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */
} eDepsOperation_Type;
/* Types of relationships between nodes
*
* This is used to provide additional hints to use when filtering
* the graph, so that we can go without doing more extensive
* data-level checks...
*/
typedef enum eDepsRelation_Type {
/* reationship type unknown/irrelevant */
DEPSREL_TYPE_STANDARD = 0,
/* root -> active scene or entity (screen, image, etc.) */
DEPSREL_TYPE_ROOT_TO_ACTIVE,
/* general datablock dependency */
DEPSREL_TYPE_DATABLOCK,
/* time dependency */
DEPSREL_TYPE_TIME,
/* component depends on results of another */
DEPSREL_TYPE_COMPONENT_ORDER,
/* relationship is just used to enforce ordering of operations
* (e.g. "init()" callback done before "exec() and "cleanup()")
*/
DEPSREL_TYPE_OPERATION,
/* relationship results from a property driver affecting property */
DEPSREL_TYPE_DRIVER,
/* relationship is something driver depends on */
DEPSREL_TYPE_DRIVER_TARGET,
/* relationship is used for transform stack
* (e.g. parenting, user transforms, constraints)
*/
DEPSREL_TYPE_TRANSFORM,
/* relationship is used for geometry evaluation
* (e.g. metaball "motherball" or modifiers)
*/
DEPSREL_TYPE_GEOMETRY_EVAL,
/* relationship is used to trigger a post-change validity updates */
DEPSREL_TYPE_UPDATE,
/* relationship is used to trigger editor/screen updates */
DEPSREL_TYPE_UPDATE_UI,
} eDepsRelation_Type;
#endif /* __DEPSGRAPH_TYPES_H__ */

@ -0,0 +1,308 @@
/*
* ***** 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 *****
*/
#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: deleting relations will remove them from the node relations set,
* but only touch the same position as we are using here, which is safe.
*/
DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
{
OBJECT_GUARDED_DELETE(rel, DepsRelation);
}
DEPSNODE_RELATIONS_ITER_END;
DEPSNODE_RELATIONS_ITER_BEGIN(this->outlinks, 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()
{
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);
BLI_assert(adt != NULL);
if (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);
}

@ -0,0 +1,243 @@
/*
* ***** 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 *****
*/
#ifndef __DEPSNODE_H__
#define __DEPSNODE_H__
#include "depsgraph_types.h"
#include "depsgraph_util_hash.h"
#include "depsgraph_util_map.h"
#include "depsgraph_util_set.h"
struct ID;
struct Scene;
struct Depsgraph;
struct DepsRelation;
struct DepsgraphCopyContext;
struct OperationDepsNode;
/* *********************************** */
/* Base-Defines for Nodes in Depsgraph */
/* All nodes in Depsgraph are descended from this. */
struct DepsNode {
/* Helper class for static typeinfo in subclasses. */
struct TypeInfo {
TypeInfo(eDepsNode_Type type, const char *tname);
eDepsNode_Type type;
eDepsNode_Class tclass;
const char *tname;
};
/* Identifier - mainly for debugging purposes. */
string name;
/* Structural type of node. */
eDepsNode_Type type;
/* Type of data/behaviour represented by node... */
eDepsNode_Class tclass;
/* Relationships between nodes
* The reason why all depsgraph nodes are descended from this type (apart
* from basic serialization benefits - from the typeinfo) is that we can have
* relationships between these nodes!
*/
typedef unordered_set<DepsRelation *> Relations;
/* Nodes which this one depends on. */
Relations inlinks;
/* Nodes which depend on this one. */
Relations outlinks;
/* Generic tag for traversal algorithms */
int done;
/* Methods. */
DepsNode();
virtual ~DepsNode();
virtual string identifier() const;
string full_identifier() const;
virtual void init(const ID * /*id*/,
const string &/*subdata*/) {}
virtual void copy(DepsgraphCopyContext * /*dcc*/,
const DepsNode * /*src*/) {}
virtual void tag_update(Depsgraph * /*graph*/) {}
virtual OperationDepsNode *get_entry_operation() { return NULL; }
virtual OperationDepsNode *get_exit_operation() { return NULL; }
};
/* Macros for common static typeinfo. */
#define DEG_DEPSNODE_DECLARE \
static const DepsNode::TypeInfo typeinfo
#define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \
const DepsNode::TypeInfo NodeType::typeinfo = DepsNode::TypeInfo(type_, tname_)
/* Generic Nodes ======================= */
struct ComponentDepsNode;
struct IDDepsNode;
/* Time Source Node. */
struct TimeSourceDepsNode : public DepsNode {
/* New "current time". */
float cfra;
/* time-offset relative to the "official" time source that this one has. */
float offset;
// TODO: evaluate() operation needed
void tag_update(Depsgraph *graph);
DEG_DEPSNODE_DECLARE;
};
/* Root Node. */
struct RootDepsNode : public DepsNode {
~RootDepsNode();
TimeSourceDepsNode *add_time_source(const string &name = "");
/* scene that this corresponds to */
Scene *scene;
/* Entrypoint node for time-changed. */
TimeSourceDepsNode *time_source;
DEG_DEPSNODE_DECLARE;
};
/* ID-Block Reference */
struct IDDepsNode : public DepsNode {
struct ComponentIDKey {
ComponentIDKey(eDepsNode_Type type, const string &name = "")
: type(type), name(name) {}
bool operator== (const ComponentIDKey &other) const
{
return type == other.type && name == other.name;
}
eDepsNode_Type type;
string name;
};
/* XXX can't specialize std::hash for this purpose, because ComponentIDKey is
* a nested type ...
*
* http://stackoverflow.com/a/951245
*/
struct component_key_hash {
bool operator() (const ComponentIDKey &key) const
{
return hash_combine(hash<int>()(key.type), hash<string>()(key.name));
}
};
typedef unordered_map<ComponentIDKey,
ComponentDepsNode*,
component_key_hash> ComponentMap;
void init(const ID *id, const string &subdata);
void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src);
~IDDepsNode();
ComponentDepsNode *find_component(eDepsNode_Type type,
const string &name = "") const;
ComponentDepsNode *add_component(eDepsNode_Type type,
const string &name = "");
void remove_component(eDepsNode_Type type, const string &name = "");
void clear_components();
void tag_update(Depsgraph *graph);
/* ID Block referenced. */
ID *id;
/* Hash to make it faster to look up components. */
ComponentMap components;
/* Layers of this node with accumulated layers of it's output relations. */
int layers;
/* Additional flags needed for scene evaluation.
* TODO(sergey): Only needed for until really granual updates
* of all the entities.
*/
int eval_flags;
DEG_DEPSNODE_DECLARE;
};
/* Subgraph Reference. */
struct SubgraphDepsNode : public DepsNode {
void init(const ID *id, const string &subdata);
void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src);
~SubgraphDepsNode();
/* Instanced graph. */
Depsgraph *graph;
/* ID-block at root of subgraph (if applicable). */
ID *root_id;
/* Number of nodes which use/reference this subgraph - if just 1, it may be
* possible to merge into main,
*/
size_t num_users;
/* (eSubgraphRef_Flag) assorted settings for subgraph node. */
int flag;
DEG_DEPSNODE_DECLARE;
};
/* Flags for subgraph node */
typedef enum eSubgraphRef_Flag {
/* Subgraph referenced is shared with another reference, so shouldn't
* free on exit.
*/
SUBGRAPH_FLAG_SHARED = (1 << 0),
/* Node is first reference to subgraph, so it can be freed when we are
* removed.
*/
SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
} eSubgraphRef_Flag;
void DEG_register_base_depsnodes();
#endif /* __DEPSNODE_H__ */

@ -0,0 +1,314 @@
/*
* ***** 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 *****
*/
#include <stdio.h>
#include <string.h>
extern "C" {
#include "BLI_utildefines.h"
#include "DNA_object_types.h"
#include "BKE_action.h"
} /* extern "C" */
#include "depsnode_component.h" /* own include */
#include "depsnode_operation.h"
#include "depsgraph_intern.h"
/* *********** */
/* Outer Nodes */
/* Standard Component Methods ============================= */
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
exit_operation(NULL)
{
}
/* Initialize 'component' node - from pointer data given */
void ComponentDepsNode::init(const ID * /*id*/,
const string & /*subdata*/)
{
/* hook up eval context? */
// XXX: maybe this needs a special API?
}
/* Copy 'component' node */
void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
const ComponentDepsNode * /*src*/)
{
#if 0 // XXX: remove all this
/* duplicate list of operation nodes */
this->operations.clear();
for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) {
const string &pchan_name = it->first;
OperationDepsNode *src_op = it->second;
/* recursive copy */
DepsNodeFactory *factory = DEG_node_get_factory(src_op);
OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op);
this->operations[pchan_name] = dst_op;
/* fix links... */
// ...
}
/* copy evaluation contexts */
//
#endif
BLI_assert(!"Not expected to be called");
}
/* Free 'component' node */
ComponentDepsNode::~ComponentDepsNode()
{
clear_operations();
}
string ComponentDepsNode::identifier() const
{
string &idname = this->owner->name;
char typebuf[7];
sprintf(typebuf, "(%d)", type);
return string(typebuf) + name + " : " + idname;
}
OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
{
OperationMap::const_iterator it = this->operations.find(key);
if (it != this->operations.end()) {
return it->second;
}
else {
fprintf(stderr, "%s: find_operation(%s) failed\n",
this->identifier().c_str(), key.identifier().c_str());
BLI_assert(!"Request for non-existing operation, should not happen");
return NULL;
}
}
OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const
{
OperationIDKey key(opcode, name);
return find_operation(key);
}
OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
{
OperationMap::const_iterator it = this->operations.find(key);
if (it != this->operations.end()) {
return it->second;
}
return NULL;
}
OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
const string &name) const
{
OperationIDKey key(opcode, name);
return has_operation(key);
}
OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name)
{
OperationDepsNode *op_node = has_operation(opcode, name);
if (!op_node) {
DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION);
op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
/* register opnode in this component's operation set */
OperationIDKey key(opcode, name);
this->operations[key] = op_node;
/* set as entry/exit node of component (if appropriate) */
if (optype == DEPSOP_TYPE_INIT) {
BLI_assert(this->entry_operation == NULL);
this->entry_operation = op_node;
}
else if (optype == DEPSOP_TYPE_POST) {
// XXX: review whether DEPSOP_TYPE_OUT is better than DEPSOP_TYPE_POST, or maybe have both?
BLI_assert(this->exit_operation == NULL);
this->exit_operation = op_node;
}
/* set backlink */
op_node->owner = this;
}
else {
fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
this->identifier().c_str(), op_node->identifier().c_str(), op_node);
BLI_assert(!"Should not happen!");
}
/* attach extra data */
op_node->evaluate = op;
op_node->optype = optype;
op_node->opcode = opcode;
op_node->name = name;
return op_node;
}
void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
{
OperationDepsNode *op_node = find_operation(opcode, name);
if (op_node) {
/* unregister */
this->operations.erase(OperationIDKey(opcode, name));
OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
}
}
void ComponentDepsNode::clear_operations()
{
for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
OperationDepsNode *op_node = it->second;
OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
}
operations.clear();
}
void ComponentDepsNode::tag_update(Depsgraph *graph)
{
OperationDepsNode *entry_op = get_entry_operation();
if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
OperationDepsNode *op_node = it->second;
op_node->tag_update(graph);
}
}
OperationDepsNode *ComponentDepsNode::get_entry_operation()
{
if (entry_operation)
return entry_operation;
else if (operations.size() == 1)
return operations.begin()->second;
return NULL;
}
OperationDepsNode *ComponentDepsNode::get_exit_operation()
{
if (exit_operation)
return exit_operation;
else if (operations.size() == 1)
return operations.begin()->second;
return NULL;
}
/* Parameter Component Defines ============================ */
DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
static DepsNodeFactoryImpl<ParametersComponentDepsNode> DNTI_PARAMETERS;
/* Animation Component Defines ============================ */
DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEPSNODE_TYPE_ANIMATION, "Animation Component");
static DepsNodeFactoryImpl<AnimationComponentDepsNode> DNTI_ANIMATION;
/* Transform Component Defines ============================ */
DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEPSNODE_TYPE_TRANSFORM, "Transform Component");
static DepsNodeFactoryImpl<TransformComponentDepsNode> DNTI_TRANSFORM;
/* Proxy Component Defines ================================ */
DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEPSNODE_TYPE_PROXY, "Proxy Component");
static DepsNodeFactoryImpl<ProxyComponentDepsNode> DNTI_PROXY;
/* Geometry Component Defines ============================= */
DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEPSNODE_TYPE_GEOMETRY, "Geometry Component");
static DepsNodeFactoryImpl<GeometryComponentDepsNode> DNTI_GEOMETRY;
/* Sequencer Component Defines ============================ */
DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEPSNODE_TYPE_SEQUENCER, "Sequencer Component");
static DepsNodeFactoryImpl<SequencerComponentDepsNode> DNTI_SEQUENCER;
/* Pose Component ========================================= */
DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEPSNODE_TYPE_EVAL_POSE, "Pose Eval Component");
static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE;
/* Bone Component ========================================= */
/* Initialize 'bone component' node - from pointer data given */
void BoneComponentDepsNode::init(const ID *id, const string &subdata)
{
/* generic component-node... */
ComponentDepsNode::init(id, subdata);
/* name of component comes is bone name */
/* TODO(sergey): This sets name to an empty string because subdata is
* empty. Is it a bug?
*/
//this->name = subdata;
/* bone-specific node data */
Object *ob = (Object *)id;
this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str());
}
DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component");
static DepsNodeFactoryImpl<BoneComponentDepsNode> DNTI_BONE;
/* Particles Component Defines ============================ */
DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEPSNODE_TYPE_EVAL_PARTICLES, "Particles Component");
static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
/* Shading Component Defines ============================ */
DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
/* Node Types Register =================================== */
void DEG_register_component_depsnodes()
{
DEG_register_node_typeinfo(&DNTI_PARAMETERS);
DEG_register_node_typeinfo(&DNTI_PROXY);
DEG_register_node_typeinfo(&DNTI_ANIMATION);
DEG_register_node_typeinfo(&DNTI_TRANSFORM);
DEG_register_node_typeinfo(&DNTI_GEOMETRY);
DEG_register_node_typeinfo(&DNTI_SEQUENCER);
DEG_register_node_typeinfo(&DNTI_EVAL_POSE);
DEG_register_node_typeinfo(&DNTI_BONE);
DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
DEG_register_node_typeinfo(&DNTI_SHADING);
}

@ -0,0 +1,197 @@
/*
* ***** 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 *****
*/
#ifndef __DEPSNODE_COMPONENT_H__
#define __DEPSNODE_COMPONENT_H__
#include "depsnode.h"
#include "depsgraph_util_hash.h"
#include "depsgraph_util_map.h"
#include "depsgraph_util_set.h"
struct ID;
struct bPoseChannel;
struct Depsgraph;
struct DepsgraphCopyContext;
struct EvaluationContext;
struct OperationDepsNode;
struct BoneComponentDepsNode;
/* ID Component - Base type for all components */
struct ComponentDepsNode : public DepsNode {
/* Key used to look up operations within a component */
struct OperationIDKey
{
eDepsOperation_Code opcode;
string name;
OperationIDKey() :
opcode(DEG_OPCODE_OPERATION), name("")
{}
OperationIDKey(eDepsOperation_Code opcode) :
opcode(opcode), name("")
{}
OperationIDKey(eDepsOperation_Code opcode, const string &name) :
opcode(opcode), name(name)
{}
string identifier() const
{
char codebuf[5];
sprintf(codebuf, "%d", opcode);
return string("OperationIDKey(") + codebuf + ", " + name + ")";
}
bool operator==(const OperationIDKey &other) const
{
return (opcode == other.opcode) && (name == other.name);
}
};
/* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ...
* http://stackoverflow.com/a/951245
*/
struct operation_key_hash {
bool operator() (const OperationIDKey &key) const
{
return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name));
}
};
/* Typedef for container of operations */
typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap;
ComponentDepsNode();
~ComponentDepsNode();
void init(const ID *id, const string &subdata);
void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src);
string identifier() const;
/* Find an existing operation, will throw an assert() if it does not exist. */
OperationDepsNode *find_operation(OperationIDKey key) const;
OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const;
/* Check operation exists and return it. */
OperationDepsNode *has_operation(OperationIDKey key) const;
OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const;
/**
* Create a new node for representing an operation and add this to graph
* \warning If an existing node is found, it will be modified. This helps when node may
* have been partially created earlier (e.g. parent ref before parent item is added)
*
* \param type: Operation node type (corresponding to context/component that it operates in)
* \param optype: Role that operation plays within component (i.e. where in eval process)
* \param op: The operation to perform
* \param name: Identifier for operation - used to find/locate it again
*/
OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name);
void remove_operation(eDepsOperation_Code opcode, const string &name);
void clear_operations();
void tag_update(Depsgraph *graph);
/* Evaluation Context Management .................. */
/* Initialize component's evaluation context used for the specified purpose */
virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
/* Free data in component's evaluation context which is used for the specified purpose
* NOTE: this does not free the actual context in question
*/
virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
OperationDepsNode *get_entry_operation();
OperationDepsNode *get_exit_operation();
IDDepsNode *owner;
OperationMap operations; /* inner nodes for this component */
OperationDepsNode *entry_operation;
OperationDepsNode *exit_operation;
// XXX: a poll() callback to check if component's first node can be started?
};
/* ---------------------------------------- */
struct ParametersComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
struct AnimationComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
struct TransformComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
struct ProxyComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
struct GeometryComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
struct SequencerComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
struct PoseComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
/* Bone Component */
struct BoneComponentDepsNode : public ComponentDepsNode {
void init(const ID *id, const string &subdata);
struct bPoseChannel *pchan; /* the bone that this component represents */
DEG_DEPSNODE_DECLARE;
};
struct ParticlesComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
struct ShadingComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
void DEG_register_component_depsnodes();
#endif /* __DEPSNODE_COMPONENT_H__ */

@ -0,0 +1,141 @@
/*
* ***** 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) 2014 Blender Foundation.
* All rights reserved.
*
* Original Author: Joshua Leung
* Contributor(s): None Yet
*
* ***** END GPL LICENSE BLOCK *****
*/
/* == OpCodes for OperationDepsNodes ==
* This file defines all the "operation codes" (opcodes) used to identify
* common operation node types. The intention of these defines is to have
* a fast and reliable way of identifying the relevant nodes within a component
* without having to use fragile dynamic strings.
*
* This file is meant to be used like UI_icons.h. That is, before including
* the file, the host file must define the DEG_OPCODE(_label) macro, which
* is responsible for converting the define into whatever form is suitable.
* Therefore, it intentionally doesn't have header guards.
*/
/* Example macro define: */
/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */
/* Generic Operations ------------------------------ */
/* Placeholder for operations which don't need special mention */
DEF_DEG_OPCODE(OPERATION)
// XXX: Placeholder while porting depsgraph code
DEF_DEG_OPCODE(PLACEHOLDER)
DEF_DEG_OPCODE(NOOP)
/* Animation, Drivers, etc. ------------------------ */
/* NLA + Action */
DEF_DEG_OPCODE(ANIMATION)
/* Driver */
DEF_DEG_OPCODE(DRIVER)
/* Proxy Inherit? */
//DEF_DEG_OPCODE(PROXY)
/* Transform --------------------------------------- */
/* Transform entry point - local transforms only */
DEF_DEG_OPCODE(TRANSFORM_LOCAL)
/* Parenting */
DEF_DEG_OPCODE(TRANSFORM_PARENT)
/* Constraints */
DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS)
//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT)
//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT)
//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE)
/* Rigidbody Sim - Perform Sim */
DEF_DEG_OPCODE(RIGIDBODY_REBUILD)
DEF_DEG_OPCODE(RIGIDBODY_SIM)
/* Rigidbody Sim - Copy Results to Object */
DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY)
/* Transform exitpoint */
DEF_DEG_OPCODE(TRANSFORM_FINAL)
/* XXX: ubereval is for temporary porting purposes only */
DEF_DEG_OPCODE(OBJECT_UBEREVAL)
/* Geometry ---------------------------------------- */
/* XXX: Placeholder - UberEval */
DEF_DEG_OPCODE(GEOMETRY_UBEREVAL)
/* Modifier */
DEF_DEG_OPCODE(GEOMETRY_MODIFIER)
/* Curve Objects - Path Calculation (used for path-following tools) */
DEF_DEG_OPCODE(GEOMETRY_PATH)
/* Pose -------------------------------------------- */
/* Init IK Trees, etc. */
DEF_DEG_OPCODE(POSE_INIT)
/* Free IK Trees + Compute Deform Matrices */
DEF_DEG_OPCODE(POSE_DONE)
/* IK/Spline Solvers */
DEF_DEG_OPCODE(POSE_IK_SOLVER)
DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER)
/* Bone -------------------------------------------- */
/* Bone local transforms - Entrypoint */
DEF_DEG_OPCODE(BONE_LOCAL)
/* Pose-space conversion (includes parent + restpose) */
DEF_DEG_OPCODE(BONE_POSE_PARENT)
/* Constraints */
DEF_DEG_OPCODE(BONE_CONSTRAINTS)
//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT)
//DEF_DEG_OPCODE(BONE_CONSTRAINT)
//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
/* Bone transforms are ready
* - "READY" This (internal) noop is used to signal that all pre-IK operations are done.
* Its role is to help mediate situations where cyclic relations may otherwise form
* (i.e. one bone in chain targetting another in same chain)
* - "DONE" This noop is used to signal that the bone's final pose transform can be read by others
*/
// TODO: deform mats could get calculated in the final_transform ops...
DEF_DEG_OPCODE(BONE_READY)
DEF_DEG_OPCODE(BONE_DONE)
/* Particles --------------------------------------- */
/* XXX: placeholder - Particle System eval */
DEF_DEG_OPCODE(PSYS_EVAL)

@ -0,0 +1,100 @@
/*
* ***** 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 *****
*/
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
} /* extern "C" */
#include "depsnode_operation.h" /* own include */
#include "depsnode_component.h"
#include "depsgraph.h"
#include "depsgraph_intern.h"
/* ******************************************************************* */
/* OpNode Identifiers Array - Exported to other depsgraph files too... */
/* identifiers for operations */
const char *DEG_OPNAMES[] = {
#define DEF_DEG_OPCODE(label) #label,
#include "depsnode_opcodes.h"
#undef DEF_DEG_OPCODE
"<Invalid>"
};
/* *********** */
/* Inner Nodes */
OperationDepsNode::OperationDepsNode() :
eval_priority(0.0f),
flag(0)
{
}
OperationDepsNode::~OperationDepsNode()
{
}
string OperationDepsNode::identifier() const
{
BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES)));
return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
}
/* Full node identifier, including owner name.
* used for logging and debug prints.
*/
string OperationDepsNode::full_identifier() const
{
string owner_str = "";
if (owner->type == DEPSNODE_TYPE_BONE) {
owner_str = owner->owner->name + "." + owner->name;
}
else {
owner_str = owner->owner->name;
}
return owner_str + "." + identifier();
}
void OperationDepsNode::tag_update(Depsgraph *graph)
{
if (flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
/* Tag for update, but also note that this was the source of an update. */
flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED);
graph->add_entry_tag(this);
}
DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
void DEG_register_operation_depsnodes()
{
DEG_register_node_typeinfo(&DNTI_OPERATION);
}

@ -0,0 +1,86 @@
/*
* ***** 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 *****
*/
#ifndef __DEPSNODE_OPERATION_H__
#define __DEPSNODE_OPERATION_H__
#include "depsnode.h"
struct ID;
struct Depsgraph;
struct DepsgraphCopyContext;
/* Flags for Depsgraph Nodes */
typedef enum eDepsOperation_Flag {
/* node needs to be updated */
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
/* node was directly modified, causing need for update */
/* XXX: intention is to make it easier to tell when we just need to take subgraphs */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
/* Operation is evaluated using CPython; has GIL and security implications... */
DEPSOP_FLAG_USES_PYTHON = (1 << 2),
} eDepsOperation_Flag;
/* Atomic Operation - Base type for all operations */
struct OperationDepsNode : public DepsNode {
OperationDepsNode();
~OperationDepsNode();
string identifier() const;
string full_identifier() const;
void tag_update(Depsgraph *graph);
bool is_noop() const { return (bool)evaluate == false; }
OperationDepsNode *get_entry_operation() { return this; }
OperationDepsNode *get_exit_operation() { return this; }
ComponentDepsNode *owner; /* component that contains the operation */
DepsEvalOperationCb evaluate; /* callback for operation */
uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */
float eval_priority;
bool scheduled;
short optype; /* (eDepsOperation_Type) stage of evaluation */
int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */
int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */
DEG_DEPSNODE_DECLARE;
};
void DEG_register_operation_depsnodes();
#endif /* __DEPSNODE_OPERATION_H__ */

@ -0,0 +1,134 @@
/*
* ***** 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) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Sergey Sharybin
*/
#include <cstdio>
#include <cstdlib>
#include <stack>
extern "C" {
#include "BLI_utildefines.h"
#include "DNA_ID.h"
#include "RNA_access.h"
#include "RNA_types.h"
}
#include "depsgraph_util_cycle.h"
#include "depsgraph.h"
#include "depsnode.h"
#include "depsnode_component.h"
#include "depsnode_operation.h"
struct StackEntry {
OperationDepsNode *node;
StackEntry *from;
DepsRelation *via_relation;
};
void deg_graph_detect_cycles(Depsgraph *graph)
{
/* Not is not visited at all during traversal. */
const int NODE_NOT_VISITED = 0;
/* Node has been visited during traversal and not in current stack. */
const int NODE_VISITED = 1;
/* Node has been visited during traversal and is in current stack. */
const int NODE_IN_STACK = 2;
std::stack<StackEntry> traversal_stack;
for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
it_op != graph->operations.end();
++it_op)
{
OperationDepsNode *node = *it_op;
bool has_inlinks = false;
for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
it_rel != node->inlinks.end();
++it_rel)
{
DepsRelation *rel = *it_rel;
if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
has_inlinks = true;
}
}
if (has_inlinks == false) {
StackEntry entry;
entry.node = node;
entry.from = NULL;
entry.via_relation = NULL;
traversal_stack.push(entry);
node->done = NODE_IN_STACK;
}
else {
node->done = NODE_NOT_VISITED;
}
}
while (!traversal_stack.empty()) {
StackEntry &entry = traversal_stack.top();
OperationDepsNode *node = entry.node;
bool all_child_traversed = true;
for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
it_rel != node->outlinks.end();
++it_rel)
{
DepsRelation *rel = *it_rel;
if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
if (to->done == NODE_IN_STACK) {
printf("Dependency cycle detected:\n");
printf(" '%s' depends on '%s' through '%s'\n",
to->full_identifier().c_str(),
node->full_identifier().c_str(),
rel->name);
StackEntry *current = &entry;
while (current->node != to) {
BLI_assert(current != NULL);
printf(" '%s' depends on '%s' through '%s'\n",
current->node->full_identifier().c_str(),
current->from->node->full_identifier().c_str(),
current->via_relation->name);
current = current->from;
}
/* TODO(sergey): So called roussian rlette cycle solver. */
rel->flag |= DEPSREL_FLAG_CYCLIC;
}
else if (to->done == NODE_NOT_VISITED) {
StackEntry new_entry;
new_entry.node = to;
new_entry.from = &entry;
new_entry.via_relation = rel;
traversal_stack.push(new_entry);
to->done = NODE_IN_STACK;
all_child_traversed = false;
break;
}
}
}
if (all_child_traversed) {
node->done = NODE_VISITED;
traversal_stack.pop();
}
}
}

@ -0,0 +1,31 @@
/*
* ***** 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) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Sergey Sharybin
*/
#ifndef __DEPSGRAPH_UTIL_CYCLE_H__
#define __DEPSGRAPH_UTIL_CYCLE_H__
struct Depsgraph;
void deg_graph_detect_cycles(Depsgraph *graph);
#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */

@ -0,0 +1,106 @@
/*
* ***** 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) 2014 Blender Foundation.
* All rights reserved.
*
* Original Author: Lukas Toenne
* Contributor(s):
*/
#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__
#define __DEPSGRAPH_UTIL_FUNCTION_H__
#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
#include <functional>
using std::function;
using namespace std::placeholders;
#define function_bind std::bind
#elif defined(HAVE_BOOST_FUNCTION_BINDINGS)
#include <boost/bind.hpp>
#include <boost/function.hpp>
using boost::function;
#define function_bind boost::bind
#else
#pragma message("No available function binding implementation. Using stub instead, disabling new depsgraph")
#ifndef WITH_LEGACY_DEPSGRAPH
# error "Unable to build new depsgraph and legacy one is disabled."
#endif
#define DISABLE_NEW_DEPSGRAPH
#include <cstdlib>
template<typename T>
class function {
public:
function() {};
function(void *) {}
operator bool() const { return false; }
bool operator== (void*) { return false; }
template<typename T1>
void operator() (T1) {
BLI_assert(!"Should not be used");
}
};
class Wrap {
public:
Wrap() {}
template <typename T>
Wrap(T /*arg*/) {}
};
template <typename T>
void *function_bind(T func,
Wrap arg1 = Wrap(),
Wrap arg2 = Wrap(),
Wrap arg3 = Wrap(),
Wrap arg4 = Wrap(),
Wrap arg5 = Wrap(),
Wrap arg6 = Wrap(),
Wrap arg7 = Wrap())
{
BLI_assert(!"Should not be used");
(void)func;
(void)arg1;
(void)arg2;
(void)arg3;
(void)arg4;
(void)arg5;
(void)arg6;
(void)arg7;
return NULL;
}
#define _1 Wrap()
#define _2 Wrap()
#define _3 Wrap()
#define _4 Wrap()
#endif
#endif /* __DEPSGRAPH_UTIL_SET_H__ */

@ -0,0 +1,66 @@
/*
* ***** 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) 2014 Blender Foundation.
* All rights reserved.
*
* Original Author: Brecht van Lommel
* Contributor(s): Lukas Toenne
*/
#ifndef __DEPSGRAPH_UTIL_HASH_H__
#define __DEPSGRAPH_UTIL_HASH_H__
#if defined(DEG_NO_UNORDERED_MAP)
# define DEG_HASH_NAMESPACE_BEGIN
# define DEG_HASH_NAMESPACE_END
#endif
#if defined(DEG_TR1_UNORDERED_MAP)
# include <tr1/unordered_map>
# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
# define DEG_HASH_NAMESPACE_END } }
using std::tr1::hash;
#endif
#if defined(DEG_STD_UNORDERED_MAP)
# include <unordered_map>
# define DEG_HASH_NAMESPACE_BEGIN namespace std {
# define DEG_HASH_NAMESPACE_END }
using std::hash;
#endif
#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
# include <unordered_map>
# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
# define DEG_HASH_NAMESPACE_END } }
using std::tr1::hash;
#endif
#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
!defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
#endif
/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
inline size_t hash_combine(size_t hash_a, size_t hash_b)
{
return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
}
#endif /* __DEPSGRAPH_UTIL_HASH_H__ */

@ -0,0 +1,61 @@
/*
* ***** 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) 2014 Blender Foundation.
* All rights reserved.
*
* Original Author: Brecht van Lommel
* Contributor(s): Lukas Toenne
*/
#ifndef __DEPSGRAPH_UTIL_MAP_H__
#define __DEPSGRAPH_UTIL_MAP_H__
#include <map>
#include "depsgraph_util_hash.h"
using std::map;
using std::pair;
#if defined(DEG_NO_UNORDERED_MAP)
# include <map>
typedef std::map unordered_map;
#endif
#if defined(DEG_TR1_UNORDERED_MAP)
# include <tr1/unordered_map>
using std::tr1::unordered_map;
#endif
#if defined(DEG_STD_UNORDERED_MAP)
# include <unordered_map>
using std::unordered_map;
#endif
#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
# include <unordered_map>
using std::tr1::unordered_map;
#endif
#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
!defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
#endif
#endif /* __DEPSGRAPH_UTIL_MAP_H__ */

@ -0,0 +1,132 @@
/*
* ***** 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) 2015 Blender Foundation.
* All rights reserved.
*
* Original Author: Sergey Sharybin
* Contributor(s): Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "depsgraph_util_pchanmap.h"
#include <stdio.h>
#include <string.h>
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
}
static void free_rootpchanmap_valueset(void *val)
{
/* Just need to free the set itself - the names stored are all references. */
GSet *values = (GSet *)val;
BLI_gset_free(values, NULL);
}
RootPChanMap::RootPChanMap()
{
/* Just create empty map. */
m_map = BLI_ghash_str_new("RootPChanMap");
}
RootPChanMap::~RootPChanMap()
{
/* Free the map, and all the value sets. */
BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset);
}
/* Debug contents of map */
void RootPChanMap::print_debug()
{
GHashIterator it1;
GSetIterator it2;
printf("Root PChan Map:\n");
GHASH_ITER(it1, m_map) {
const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
printf(" %s : { ", item);
GSET_ITER(it2, values) {
const char *val = (const char *)BLI_gsetIterator_getKey(&it2);
printf("%s, ", val);
}
printf("}\n");
}
}
/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
if (BLI_ghash_haskey(m_map, bone)) {
/* Add new entry, but only add the root if it doesn't already
* exist in there.
*/
GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone);
BLI_gset_add(values, (void *)root);
}
else {
/* Create new set and mapping. */
GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p,
BLI_ghashutil_strcmp,
"RootPChanMap Value Set");
BLI_ghash_insert(m_map, (void *)bone, (void *)values);
/* Add new entry now. */
BLI_gset_insert(values, (void *)root);
}
}
/* Check if there's a common root bone between two bones. */
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
{
/* Ensure that both are in the map... */
if (BLI_ghash_haskey(m_map, bone1) == false) {
//fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
//print_debug();
return false;
}
if (BLI_ghash_haskey(m_map, bone2) == false) {
//fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
//print_debug();
return false;
}
GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1);
GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2);
GSetIterator it1, it2;
GSET_ITER(it1, bone1_roots) {
GSET_ITER(it2, bone2_roots) {
const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1);
const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2);
if (strcmp(v1, v2) == 0) {
//fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2);
return true;
}
}
}
//fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
return false;
}

@ -0,0 +1,55 @@
/*
* ***** 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) 2015 Blender Foundation.
* All rights reserved.
*
* Original Author: Sergey Sharybin
* Contributor(s): Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef ___DEPSGRAPH_UTIL_PCHANMAP_H__
#define ___DEPSGRAPH_UTIL_PCHANMAP_H__
struct RootPChanMap {
/* ctor and dtor - Create and free the internal map respectively. */
RootPChanMap();
~RootPChanMap();
/* Debug contents of map. */
void print_debug();
/* Add a mapping. */
void add_bone(const char *bone, const char *root);
/* Check if there's a common root bone between two bones. */
bool has_common_root(const char *bone1, const char *bone2);
private:
/* The actual map:
* - Keys are "strings" (const char *) - not dynamically allocated.
* - Values are "sets" (const char *) - not dynamically allocated.
*
* We don't use the C++ maps here, as it's more convenient to use
* Blender's GHash and be able to compare by-value instead of by-ref.
*/
struct GHash *m_map;
};
#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */

@ -0,0 +1,60 @@
/*
* ***** 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) 2014 Blender Foundation.
* All rights reserved.
*
* Original Author: Brecht van Lommel
* Contributor(s): Lukas Toenne
*/
#ifndef __DEPSGRAPH_UTIL_SET_H__
#define __DEPSGRAPH_UTIL_SET_H__
#include <set>
#include "depsgraph_util_hash.h"
using std::set;
#if defined(DEG_NO_UNORDERED_MAP)
# include <set>
typedef std::set unordered_set;
#endif
#if defined(DEG_TR1_UNORDERED_MAP)
# include <tr1/unordered_set>
using std::tr1::unordered_set;
#endif
#if defined(DEG_STD_UNORDERED_MAP)
# include <unordered_set>
using std::unordered_set;
#endif
#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
# include <unordered_set>
using std::tr1::unordered_set;
#endif
#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
!defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
#endif
#endif /* __DEPSGRAPH_UTIL_SET_H__ */

@ -0,0 +1,133 @@
/*
* ***** 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) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Lukas Toenne
* Sergey Sharybin,
*/
extern "C" {
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "DNA_ID.h"
#include "RNA_access.h"
#include "RNA_types.h"
}
#include "depsgraph_util_transitive.h"
#include "depsgraph.h"
#include "depsnode.h"
#include "depsnode_component.h"
#include "depsnode_operation.h"
/* -------------------------------------------------- */
/* Performs a transitive reduction to remove redundant relations.
* http://en.wikipedia.org/wiki/Transitive_reduction
*
* XXX The current implementation is somewhat naive and has O(V*E) worst case
* runtime.
* A more optimized algorithm can be implemented later, e.g.
*
* http://www.sciencedirect.com/science/article/pii/0304397588900321/pdf?md5=3391e309b708b6f9cdedcd08f84f4afc&pid=1-s2.0-0304397588900321-main.pdf
*
* Care has to be taken to make sure the algorithm can handle the cyclic case
* too! (unless we can to prevent this case early on).
*/
enum {
OP_VISITED = 1,
OP_REACHABLE = 2,
};
static void deg_graph_tag_paths_recursive(DepsNode *node)
{
if (node->done & OP_VISITED)
return;
node->done |= OP_VISITED;
for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin();
it != node->inlinks.end();
++it)
{
DepsRelation *rel = *it;
deg_graph_tag_paths_recursive(rel->from);
/* Do this only in inlinks loop, so the target node does not get
* flagged.
*/
rel->from->done |= OP_REACHABLE;
}
}
void deg_graph_transitive_reduction(Depsgraph *graph)
{
for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin();
it_target != graph->operations.end();
++it_target)
{
OperationDepsNode *target = *it_target;
/* Clear tags. */
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
node->done = 0;
}
/* mark nodes from which we can reach the target
* start with children, so the target node and direct children are not
* flagged.
*/
target->done |= OP_VISITED;
for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin();
it != target->inlinks.end();
++it)
{
DepsRelation *rel = *it;
deg_graph_tag_paths_recursive(rel->from);
}
/* Eemove redundant paths to the target. */
for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
it_rel != target->inlinks.end();
)
{
DepsRelation *rel = *it_rel;
/* Increment in advance, so we can safely remove the relation. */
++it_rel;
if (rel->from->type == DEPSNODE_TYPE_TIMESOURCE) {
/* HACK: time source nodes don't get "done" flag set/cleared. */
/* TODO: there will be other types in future, so iterators above
* need modifying.
*/
}
else if (rel->from->done & OP_REACHABLE) {
OBJECT_GUARDED_DELETE(rel, DepsRelation);
}
}
}
}

@ -0,0 +1,32 @@
/*
* ***** 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) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Lukas Toenne
* Sergey Sharybin,
*/
#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__
#define __DEPSGRAPH_UTIL_TRANSITIVE_H__
struct Depsgraph;
void deg_graph_transitive_reduction(Depsgraph *graph);
#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */

@ -30,6 +30,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
../../depsgraph
../../../../intern/guardedalloc
../../../../intern/glew-mx
../../../../intern/smoke/extern

@ -48,6 +48,7 @@ incs = [
'../../makesrna',
'../../render/extern/include',
'../../windowmanager',
'../../depsgraph',
]
if env['WITH_BF_PYTHON']:

@ -74,6 +74,8 @@
# include "BPY_extern.h"
#endif
#include "DEG_depsgraph.h"
#include "view3d_intern.h" /* own include */
/* ******************** manage regions ********************* */
@ -931,7 +933,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
(ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
(v3d->drawtype == OB_TEXTURE &&
(scene->gm.matmode == GAME_MAT_GLSL ||
BKE_scene_use_new_shading_nodes(scene))))
BKE_scene_use_new_shading_nodes(scene))) ||
!DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
@ -954,7 +957,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
switch (wmn->data) {
case ND_LIGHTING:
if ((v3d->drawtype == OB_MATERIAL) ||
(v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)))
(v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) ||
!DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}

@ -55,6 +55,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
if(WITH_LEGACY_DEPSGRAPH)
add_definitions(-DWITH_LEGACY_DEPSGRAPH)
endif()
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}")

@ -50,4 +50,7 @@ defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
if env['WITH_BF_LEGACY_DEPSGRAPH']:
defs.append('WITH_LEGACY_DEPSGRAPH')
env.BlenderLib ( 'bf_editors_transform', sources, incs, defs, libtype=['core'], priority=[40] )

@ -5362,7 +5362,9 @@ static void set_trans_object_base_flags(TransInfo *t)
}
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@ -5439,7 +5441,9 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
DAG_scene_relations_update(G.main, t->scene);
#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */

@ -1401,6 +1401,7 @@ typedef struct Scene {
void *fps_info; /* (runtime) info/cache used for presenting playback framerate info to the user */
/* none of the dependency graph vars is mean to be saved */
struct Depsgraph *depsgraph;
struct DagForest *theDag;
short dagflags;
short recalc; /* recalc = counterpart of ob->recalc */

@ -47,6 +47,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../bmesh',
'../depsgraph',
'../editors/include',
'../gpu',
'../ikplugin',

@ -45,6 +45,7 @@ set(DEFSRC
rna_context.c
rna_controller.c
rna_curve.c
rna_depsgraph.c
rna_dynamicpaint.c
rna_fcurve.c
rna_fluidsim.c
@ -307,6 +308,7 @@ blender_include_dirs(
../../blenlib
../../bmesh
../../blenfont
../../depsgraph
../../gpu
../../imbuf
../../ikplugin

@ -66,6 +66,7 @@ incs = [
'../../blenkernel',
'../../blenlib',
'../../bmesh',
'../../depsgraph',
'../../editors/include',
'../../gpu',
'../../ikplugin',

@ -3293,6 +3293,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_context.c", NULL, RNA_def_context},
{"rna_controller.c", "rna_controller_api.c", RNA_def_controller},
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve},
{"rna_depsgraph.c", NULL, RNA_def_depsgraph},
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
{"rna_fluidsim.c", NULL, RNA_def_fluidsim},

@ -0,0 +1,112 @@
/*
* ***** 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.
*
* Contributor(s): Blender Foundation (2014).
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/makesrna/intern/rna_depsgraph.c
* \ingroup RNA
*/
#include <stdlib.h>
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "rna_internal.h"
#include "DEG_depsgraph.h"
#include "BKE_depsgraph.h"
#ifdef RNA_RUNTIME
#include "BKE_report.h"
#include "DEG_depsgraph_debug.h"
static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename)
{
FILE *f = fopen(filename, "w");
if (f == NULL)
return;
DEG_debug_graphviz(graph, f, "Depsgraph", false);
fclose(f);
}
static void rna_Depsgraph_debug_rebuild(Depsgraph *UNUSED(graph), Main *bmain)
{
Scene *sce;
DAG_relations_tag_update(bmain);
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
DAG_scene_relations_rebuild(bmain, sce);
DEG_graph_on_visible_update(bmain, sce);
}
}
static void rna_Depsgraph_debug_stats(Depsgraph *graph, ReportList *reports)
{
size_t outer, ops, rels;
DEG_stats_simple(graph, &outer, &ops, &rels);
// XXX: report doesn't seem to work
printf("Approx %lu Operations, %lu Relations, %lu Outer Nodes\n",
ops, rels, outer);
BKE_reportf(reports, RPT_WARNING, "Approx. %lu Operations, %lu Relations, %lu Outer Nodes",
ops, rels, outer);
}
#else
static void rna_def_depsgraph(BlenderRNA *brna)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
srna = RNA_def_struct(brna, "Depsgraph", NULL);
RNA_def_struct_ui_text(srna, "Dependency Graph", "");
func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz");
parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
"File in which to store graphviz debug output");
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "debug_rebuild", "rna_Depsgraph_debug_rebuild");
RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "debug_stats", "rna_Depsgraph_debug_stats");
RNA_def_function_ui_description(func, "Report the number of elements in the Dependency Graph");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
}
void RNA_def_depsgraph(BlenderRNA *brna)
{
rna_def_depsgraph(brna);
}
#endif

@ -140,6 +140,7 @@ void RNA_def_constraint(struct BlenderRNA *brna);
void RNA_def_context(struct BlenderRNA *brna);
void RNA_def_controller(struct BlenderRNA *brna);
void RNA_def_curve(struct BlenderRNA *brna);
void RNA_def_depsgraph(struct BlenderRNA *brna);
void RNA_def_dynamic_paint(struct BlenderRNA *brna);
void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);

@ -87,6 +87,8 @@ static EnumPropertyItem space_items[] = {
#include "MEM_guardedalloc.h"
#include "DEG_depsgraph.h"
/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
float *mat, float *mat_ret, int from, int to)
@ -191,8 +193,8 @@ static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int e
static void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce, int settings)
{
bool for_render = (settings == DAG_EVAL_RENDER);
EvaluationContext eval_ctx = {0};
eval_ctx.mode = settings;
EvaluationContext eval_ctx;
DEG_evaluation_context_init(&eval_ctx, settings);
if (!(ob->transflag & OB_DUPLI)) {
BKE_report(reports, RPT_ERROR, "Object does not have duplis");

@ -6525,6 +6525,11 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ColorManagedSequencerColorspaceSettings");
RNA_def_property_ui_text(prop, "Sequencer Color Space Settings", "Settings of color space sequencer is working in");
/* Dependency Graph */
prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Depsgraph");
RNA_def_property_ui_text(prop, "Dependency Graph", "Dependencies in the scene data");
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);

@ -30,6 +30,7 @@ set(INC
../blenkernel
../blenlib
../blenfont
../depsgraph
../makesdna
../makesrna
../bmesh

@ -40,6 +40,7 @@ incs = [
'../include',
'../blenlib',
'../blenfont',
'../depsgraph',
'../makesdna',
'../makesrna',
'../blenkernel',

@ -115,6 +115,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
ArmatureModifierData *amd = (ArmatureModifierData *)md;
if (amd->object != NULL) {
DEG_add_object_relation(node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
}
}
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@ -208,6 +220,7 @@ ModifierTypeInfo modifierType_Armature = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -135,6 +135,28 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
ArrayModifierData *amd = (ArrayModifierData *)md;
if (amd->start_cap != NULL) {
DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap");
}
if (amd->end_cap != NULL) {
DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap");
}
if (amd->curve_ob) {
DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve");
DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
}
if (amd->offset_ob != NULL) {
DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset");
}
}
static float vertarray_size(const MVert *mvert, int numVerts, int axis)
{
int i;
@ -771,6 +793,7 @@ ModifierTypeInfo modifierType_Array = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -213,6 +213,7 @@ ModifierTypeInfo modifierType_Bevel = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,

@ -89,6 +89,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *ob,
struct DepsNodeHandle *node)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
if (bmd->object != NULL) {
DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
}
/* We need own transformation as well. */
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
}
#ifdef WITH_MOD_BOOLEAN
static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation)
{
@ -193,6 +208,7 @@ ModifierTypeInfo modifierType_Boolean = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -329,6 +329,7 @@ ModifierTypeInfo modifierType_Build = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -121,6 +121,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
CastModifierData *cmd = (CastModifierData *)md;
if (cmd->object != NULL) {
DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
}
}
static void sphere_do(
CastModifierData *cmd, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
@ -500,6 +512,7 @@ ModifierTypeInfo modifierType_Cast = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -140,6 +140,27 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
Object *ob,
struct DepsNodeHandle *node)
{
ClothModifierData *clmd = (ClothModifierData *)md;
if (clmd != NULL) {
Base *base;
for (base = scene->base.first; base; base = base->next) {
Object *ob1 = base->object;
if (ob1 != ob) {
CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
if (coll_clmd) {
DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier");
}
}
}
}
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
CustomDataMask dataMask = 0;
@ -251,6 +272,7 @@ ModifierTypeInfo modifierType_Cloth = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -241,6 +241,7 @@ ModifierTypeInfo modifierType_Collision = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -760,6 +760,7 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -45,6 +45,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@ -108,6 +109,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
CurveModifierData *cmd = (CurveModifierData *)md;
if (cmd->object != NULL) {
/* TODO(sergey): Need to do the same eval_flags trick for path
* as happening in legacy depsgraph callback.
*/
/* TODO(sergey): Currently path is evaluated as a part of modifier stack,
* might be changed in the future.
*/
DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
DEG_add_special_eval_flag(scene->depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
}
}
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@ -156,6 +176,7 @@ ModifierTypeInfo modifierType_Curve = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -147,6 +147,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
if (dtmd->ob_source != NULL) {
DEG_add_object_relation(node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
}
}
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
@ -235,6 +247,7 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,

@ -224,6 +224,7 @@ ModifierTypeInfo modifierType_Decimate = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -171,6 +171,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *ob,
struct DepsNodeHandle *node)
{
DisplaceModifierData *dmd = (DisplaceModifierData *)md;
if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) {
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
}
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
DisplaceModifierData *dmd, Object *ob,
@ -302,6 +317,7 @@ ModifierTypeInfo modifierType_Displace = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,

@ -38,6 +38,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@ -135,6 +136,26 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
Object *ob,
struct DepsNodeHandle *node)
{
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
/* Add relation from canvases to all brush objects. */
if (pmd->canvas != NULL) {
Base *base = scene->base.first;
for (; base; base = base->next) {
DynamicPaintModifierData *pmd2 =
(DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
if (pmd2 && pmd2->brush && ob != base->object) {
DEG_add_object_relation(node, base->object, DEG_OB_COMP_TRANSFORM, "Dynamic Paint Brush");
}
}
}
}
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@ -187,6 +208,7 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -158,6 +158,7 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -1058,6 +1058,7 @@ ModifierTypeInfo modifierType_Explode = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -44,6 +44,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MOD_fluidsim_util.h"
#include "MEM_guardedalloc.h"
@ -126,6 +127,32 @@ static void updateDepgraph(
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
Object *ob,
struct DepsNodeHandle *node)
{
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
if (fluidmd && fluidmd->fss) {
if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
Base *base;
for (base = scene->base.first; base; base = base->next) {
Object *ob1 = base->object;
if (ob1 != ob) {
FluidsimModifierData *fluidmdtmp =
(FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
/* Only put dependencies from NON-DOMAIN fluids in here. */
if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
}
}
}
}
}
}
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@ -154,6 +181,7 @@ ModifierTypeInfo modifierType_Fluidsim = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -129,6 +129,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
HookModifierData *hmd = (HookModifierData *)md;
if (hmd->object != NULL) {
if (hmd->subtarget[0]) {
/* TODO(sergey): Hpw do we add relation to bone here? */
//DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_EVAL_POSE, "Hook Modifier");
DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
}
else {
DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
}
}
struct HookData_cb {
float (*vertexCos)[3];
@ -403,6 +422,7 @@ ModifierTypeInfo modifierType_Hook = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -862,6 +862,7 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -716,6 +716,7 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* freeData */ NULL,
/* isDisabled */ is_disabled,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -107,6 +107,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
LatticeModifierData *lmd = (LatticeModifierData *)md;
if (lmd->object != NULL) {
DEG_add_object_relation(node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
}
}
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@ -155,6 +167,7 @@ ModifierTypeInfo modifierType_Lattice = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -50,6 +50,7 @@
#include "BKE_deform.h"
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "BLI_strict_flags.h"
@ -94,6 +95,22 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
MaskModifierData *mmd = (MaskModifierData *)md;
if (mmd->ob_arm) {
bArmature *arm = (bArmature *)mmd->ob_arm->data;
/* Tag relationship in depsgraph, but also on the armature. */
/* TODO(sergey): Is it a proper relation here? */
DEG_add_object_relation(node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
arm->flag |= ARM_HAS_VIZ_DEPS;
}
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag UNUSED(flag))
@ -385,6 +402,7 @@ ModifierTypeInfo modifierType_Mask = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -313,6 +313,7 @@ ModifierTypeInfo modifierType_MeshCache = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

@ -139,6 +139,19 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
if (mmd->object != NULL) {
/* TODO(sergey): Do we need transform component here? */
DEG_add_object_relation(node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier");
}
}
static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float vec[3])
{
MDefCell *cell;
@ -521,6 +534,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -43,7 +43,9 @@
#include "BKE_deform.h"
#include "MEM_guardedalloc.h"
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@ -88,6 +90,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
MirrorModifierData *mmd = (MirrorModifierData *)md;
if (mmd->mirror_ob != NULL) {
DEG_add_object_relation(node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
}
}
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
Object *ob,
DerivedMesh *dm,
@ -361,6 +375,7 @@ ModifierTypeInfo modifierType_Mirror = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,

@ -162,6 +162,7 @@ ModifierTypeInfo modifierType_Multires = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,

Some files were not shown because too many files have changed in this diff Show More