Depsgraph: refactor tagging after time changes

This reverts {rB1693a5efe91999b60b3dc0bdff727473b3bd00bb}
and implements an alternative solution.

The old patch had the problem that the depsgraph would always
evaluate at the current frame of the original scene (even when
`DEG_evaluate_on_framechange` was used). Now it is possible
to evaluate the depsgraph at a specific frame without having to
change the original scene.

Reviewers: sergey, sybren

Differential Revision: https://developer.blender.org/D8616
This commit is contained in:
Jacques Lucke 2020-08-20 16:29:34 +02:00
parent 948e080fc5
commit 263148dbac
Notes: blender-bot 2023-02-14 09:29:42 +01:00
Referenced by issue #95246, Undo bone rotation after previous frame/keyframe jump operators undoes frame jump as well (frame in UI is still the same though)
Referenced by issue #82769, Crash rendering particle animation with particle caches [disk cache works though]
Referenced by issue #80166, Animating Shape Key Max/Min Range works in viewport but not when rendering
Referenced by issue #80035, Crash to desktop with creating a new scene with a motion tracking file loaded
Referenced by issue #71234, Custom property doesnt update when rendering animation
Referenced by issue #66913, Issue with Undoing after using next/previous keyframe shortcut.
10 changed files with 67 additions and 55 deletions

View File

@ -127,6 +127,12 @@ void DEG_graph_id_tag_update(struct Main *bmain,
struct ID *id,
int flag);
/* Tag all dependency graphs when time has changed. */
void DEG_time_tag_update(struct Main *bmain);
/* Tag a dependency graph when time has changed. */
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph);
/* Mark a particular datablock type as having changing. This does
* not cause any updates but is used by external render engines to detect if for
* example a datablock was removed. */
@ -155,8 +161,6 @@ void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime);
/* Data changed recalculation entry point. */
void DEG_evaluate_on_refresh(Depsgraph *graph);
bool DEG_needs_eval(Depsgraph *graph);
/* Editors Integration -------------------------- */
/* Mechanism to allow editors to be informed of depsgraph updates,

View File

@ -63,7 +63,6 @@ namespace deg {
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(nullptr),
need_update(true),
need_update_time(false),
bmain(bmain),
scene(scene),
view_layer(view_layer),
@ -103,6 +102,11 @@ TimeSourceNode *Depsgraph::find_time_source() const
return time_source;
}
void Depsgraph::tag_time_source()
{
time_source->tag_update(this, DEG_UPDATE_SOURCE_TIME);
}
IDNode *Depsgraph::find_id_node(const ID *id) const
{
return id_hash.lookup_default(id, nullptr);

View File

@ -68,6 +68,7 @@ struct Depsgraph {
TimeSourceNode *add_time_source();
TimeSourceNode *find_time_source() const;
void tag_time_source();
IDNode *find_id_node(const ID *id) const;
IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr);
@ -121,10 +122,6 @@ struct Depsgraph {
/* Nodes which have been tagged as "directly modified". */
Set<OperationNode *> entry_tags;
/* Special entry tag for time source. Allows to tag invisible dependency graphs for update when
* scene frame changes, so then when dependency graph becomes visible it is on a proper state. */
bool need_update_time;
/* Convenience Data ................... */
/* XXX: should be collected after building (if actually needed?) */

View File

@ -47,38 +47,37 @@
namespace deg = blender::deg;
static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph)
{
/* Update the time on the cow scene. */
if (deg_graph->scene_cow) {
BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
}
deg::deg_graph_flush_updates(deg_graph);
deg::deg_evaluate_on_refresh(deg_graph);
}
/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene);
/* Update time in scene. */
if (deg_graph->scene_cow) {
BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
const Scene *scene = DEG_get_input_scene(graph);
const float ctime = BKE_scene_frame_get(scene);
if (ctime != deg_graph->ctime) {
deg_graph->tag_time_source();
deg_graph->ctime = ctime;
}
deg::deg_graph_flush_updates(deg_graph);
deg::deg_evaluate_on_refresh(deg_graph);
deg_graph->need_update_time = false;
deg_flush_updates_and_refresh(deg_graph);
}
/* Frame-change happened for root scene that graph belongs to. */
void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
deg_graph->tag_time_source();
deg_graph->ctime = ctime;
deg_graph->need_update_time = true;
deg::deg_graph_flush_updates(deg_graph);
/* Update time in scene. */
if (deg_graph->scene_cow) {
BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
}
/* Perform recalculation updates. */
deg::deg_evaluate_on_refresh(deg_graph);
deg_graph->need_update_time = false;
}
bool DEG_needs_eval(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
return !deg_graph->entry_tags.is_empty() || deg_graph->need_update_time;
deg_flush_updates_and_refresh(deg_graph);
}

View File

@ -66,6 +66,7 @@
#include "intern/node/deg_node_factory.h"
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
#include "intern/node/deg_node_time.h"
namespace deg = blender::deg;
@ -230,9 +231,6 @@ void depsgraph_tag_to_component_opcode(const ID *id,
case ID_RECALC_SOURCE:
*component_type = NodeType::PARAMETERS;
break;
case ID_RECALC_TIME:
BLI_assert(!"Should be handled outside of this function");
break;
case ID_RECALC_ALL:
case ID_RECALC_PSYS_ALL:
BLI_assert(!"Should not happen");
@ -372,12 +370,6 @@ void graph_id_tag_update_single_flag(Main *bmain,
}
return;
}
if (tag == ID_RECALC_TIME) {
if (graph != nullptr) {
graph->need_update_time = true;
}
return;
}
/* Get description of what is to be tagged. */
NodeType component_type;
OperationCode operation_code;
@ -462,8 +454,8 @@ const char *update_source_as_string(eUpdateSource source)
int deg_recalc_flags_for_legacy_zero()
{
return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE |
ID_RECALC_TIME | ID_RECALC_EDITORS);
return ID_RECALC_ALL &
~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE | ID_RECALC_EDITORS);
}
int deg_recalc_flags_effective(Depsgraph *graph, int flags)
@ -734,8 +726,6 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "AUDIO";
case ID_RECALC_PARAMETERS:
return "PARAMETERS";
case ID_RECALC_TIME:
return "TIME";
case ID_RECALC_SOURCE:
return "SOURCE";
case ID_RECALC_ALL:
@ -772,6 +762,19 @@ void DEG_graph_id_tag_update(struct Main *bmain,
deg::graph_id_tag_update(bmain, graph, id, flag, deg::DEG_UPDATE_SOURCE_USER_EDIT);
}
void DEG_time_tag_update(struct Main *bmain)
{
for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) {
DEG_graph_time_tag_update(reinterpret_cast<::Depsgraph *>(depsgraph));
}
}
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
deg_graph->tag_time_source();
}
/* Mark a particular datablock type as having changing. */
void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)
{

View File

@ -357,14 +357,9 @@ void deg_graph_flush_updates(Depsgraph *graph)
BLI_assert(graph != nullptr);
Main *bmain = graph->bmain;
graph->time_source->flush_update_tag(graph);
/* Nothing to update, early out. */
if (graph->need_update_time) {
const Scene *scene_orig = graph->scene;
const float ctime = BKE_scene_frame_get(scene_orig);
TimeSourceNode *time_source = graph->find_time_source();
graph->ctime = ctime;
time_source->tag_update(graph, DEG_UPDATE_SOURCE_TIME);
}
if (graph->entry_tags.is_empty()) {
return;
}
@ -412,6 +407,8 @@ void deg_graph_clear_tags(Depsgraph *graph)
}
/* Clear any entry tags which haven't been flushed. */
graph->entry_tags.clear();
graph->time_source->tagged_for_update = false;
}
} // namespace deg

View File

@ -31,8 +31,16 @@
namespace blender {
namespace deg {
void TimeSourceNode::tag_update(Depsgraph *graph, eUpdateSource /*source*/)
void TimeSourceNode::tag_update(Depsgraph * /*graph*/, eUpdateSource /*source*/)
{
tagged_for_update = true;
}
void TimeSourceNode::flush_update_tag(Depsgraph *graph)
{
if (!tagged_for_update) {
return;
}
for (Relation *rel : outlinks) {
Node *node = rel->to;
node->tag_update(graph, DEG_UPDATE_SOURCE_TIME);

View File

@ -30,10 +30,14 @@ namespace deg {
/* Time Source Node. */
struct TimeSourceNode : public Node {
bool tagged_for_update = false;
// TODO: evaluate() operation needed
virtual void tag_update(Depsgraph *graph, eUpdateSource source) override;
void flush_update_tag(Depsgraph *graph);
DEG_DEPSNODE_DECLARE;
};

View File

@ -1576,7 +1576,7 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
{
Scene *scene = DEG_get_input_scene(depsgraph);
DEG_id_tag_update_ex(bmain, &scene->id, ID_RECALC_TIME);
DEG_time_tag_update(bmain);
#ifdef DURIAN_CAMERA_SWITCH
void *camera = BKE_scene_camera_switch_find(scene);

View File

@ -686,10 +686,6 @@ typedef enum IDRecalcFlag {
ID_RECALC_PARAMETERS = (1 << 21),
/* Makes it so everything what depends on time.
* Basically, the same what changing frame in a timeline will do. */
ID_RECALC_TIME = (1 << 22),
/* Input has changed and datablock is to be reload from disk.
* Applies to movie clips to inform that copy-on-written version is to be refreshed for the new
* input file or for color space changes. */