Fix #139501: VSE: Build separate dependency graph for scene strip previews

Currently, the scene strip preview uses the existing dependency
graph built for that scene. This was not a big issue before
the sequencer scene was introduced, because the user would have
to create two main Blender windows to run into problems.
Now with the sequencer scene, it's possible to look at the scene
of a scene strip within the same window.
When the user is editing the scene (e.g. moving an animated object)
any open sequencer preview will cause the edits to be flushed.
This can e.g. result in visual jumping of animated objects, and more.

This PR attempts to fix the issue in a straightforward way: Use
a separate dependency graph for rendering the sequencer preview.
While this fixes the immediate issues, there are some consequences:
* The memory usage of the scene dependency graph _can_ roughly
  double (since there are now likely two instances of the same
   dependency graph). Because of implicit sharing, unmodified data
   will not be copied. But for example modifiers on meshes would
   currently create two copies of the evaluated data in the two
   dependency graphs.
* Creating the dependency graph can be costly, which will cause the
  first frame that the scene has to render to be slower.

Note: The current code changes some properties of the original scene
like the frame, subframe etc. before rendering and then restores
the original state. In theory, this part of the code can be removed,
but may be a bit too risky for just a fix. This should be improved
at a later stage.

Also resolves #146769, #139501.

Pull Request: https://projects.blender.org/blender/blender/pulls/147457
This commit is contained in:
Falk David
2025-10-13 18:29:28 +02:00
committed by Falk David
parent f75658110a
commit 1b73a53d0c
3 changed files with 40 additions and 4 deletions

View File

@@ -34,9 +34,19 @@ class CompositorRuntime {
~CompositorRuntime();
};
/* Runtime data specific to the sequencer, e.g. when using scene strips. */
class SequencerRuntime {
public:
Depsgraph *depsgraph = nullptr;
~SequencerRuntime();
};
class SceneRuntime : NonCopyable, NonMovable {
public:
CompositorRuntime compositor;
SequencerRuntime sequencer;
};
} // namespace blender::bke

View File

@@ -114,6 +114,7 @@
using blender::bke::CompositorRuntime;
using blender::bke::SceneRuntime;
using blender::bke::SequencerRuntime;
CompositorRuntime::~CompositorRuntime()
{
@@ -122,6 +123,11 @@ CompositorRuntime::~CompositorRuntime()
}
}
SequencerRuntime::~SequencerRuntime()
{
DEG_graph_free(depsgraph);
}
CurveMapping *BKE_sculpt_default_cavity_curve()
{

View File

@@ -38,8 +38,11 @@
#include "BKE_mask.h"
#include "BKE_movieclip.h"
#include "BKE_scene.hh"
#include "BKE_scene_runtime.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_build.hh"
#include "DEG_depsgraph_debug.hh"
#include "DEG_depsgraph_query.hh"
#include "IMB_colormanagement.hh"
@@ -1384,6 +1387,26 @@ static ImBuf *seq_render_mask_strip(const RenderData *context, Strip *strip, flo
context->depsgraph, context->rectx, context->recty, strip->mask, frame_index, make_float);
}
static Depsgraph *get_depsgraph_for_scene_strip(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Depsgraph *depsgraph = scene->runtime->sequencer.depsgraph;
if (!depsgraph) {
/* Create a new depsgraph for the sequencer preview. Use viewport evaluation, because this
* depsgraph is not used during final render. */
scene->runtime->sequencer.depsgraph = DEG_graph_new(
bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
depsgraph = scene->runtime->sequencer.depsgraph;
DEG_debug_name_set(depsgraph, "SEQ_SCENE_STRIP");
}
if (DEG_get_input_view_layer(depsgraph) != view_layer) {
DEG_graph_replace_owners(depsgraph, bmain, scene, view_layer);
DEG_graph_tag_relations_update(depsgraph);
}
return depsgraph;
}
static ImBuf *seq_render_scene_strip_ex(const RenderData *context,
Strip *strip,
float frame_index,
@@ -1441,10 +1464,8 @@ static ImBuf *seq_render_scene_strip_ex(const RenderData *context,
#endif
const bool have_comp = (scene->r.scemode & R_DOCOMP) && scene->compositing_node_group;
/* Get view layer for the strip. */
ViewLayer *view_layer = BKE_view_layer_default_render(scene);
/* Depsgraph will be nullptr when doing rendering. */
Depsgraph *depsgraph = nullptr;
Depsgraph *depsgraph = get_depsgraph_for_scene_strip(context->bmain, scene, view_layer);
BKE_scene_frame_set(scene, frame);
@@ -1485,7 +1506,6 @@ static ImBuf *seq_render_scene_strip_ex(const RenderData *context,
}
/* opengl offscreen render */
depsgraph = BKE_scene_ensure_depsgraph(context->bmain, scene, view_layer);
BKE_scene_graph_update_for_newframe(depsgraph);
Object *camera_eval = DEG_get_evaluated(depsgraph, camera);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);