From 1b73a53d0c9a698825b0251a6b29207cdf540e80 Mon Sep 17 00:00:00 2001 From: Falk David Date: Mon, 13 Oct 2025 18:29:28 +0200 Subject: [PATCH] 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 --- .../blender/blenkernel/BKE_scene_runtime.hh | 10 +++++++ source/blender/blenkernel/intern/scene.cc | 6 ++++ source/blender/sequencer/intern/render.cc | 28 ++++++++++++++++--- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/BKE_scene_runtime.hh b/source/blender/blenkernel/BKE_scene_runtime.hh index 6e11a3fb652..9992bd16cc0 100644 --- a/source/blender/blenkernel/BKE_scene_runtime.hh +++ b/source/blender/blenkernel/BKE_scene_runtime.hh @@ -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 diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 04d9d708168..2adeea30ee2 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -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() { diff --git a/source/blender/sequencer/intern/render.cc b/source/blender/sequencer/intern/render.cc index 3e11c569eae..ba83e720379 100644 --- a/source/blender/sequencer/intern/render.cc +++ b/source/blender/sequencer/intern/render.cc @@ -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);