From 60d0cfdfe4d0d8104606a26dccffea635444ca60 Mon Sep 17 00:00:00 2001 From: John Kiril Swenson Date: Thu, 16 Oct 2025 01:51:01 +0200 Subject: [PATCH 1/2] Fix #147701: VSE: Can't select markers when scene and sequencer scene differ Add a simple check to the Marker keymap poll. Since there's no `bContext` passed to the function we can reconstruct it from the workspace. We can exit early if there is no sequencer scene (when no markers are guaranteed). View layer can remain the same since it only applies in the `SPACE_ACTION` case. Pull Request: https://projects.blender.org/blender/blender/pulls/147903 --- .../windowmanager/intern/wm_event_system.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 16ff632932d..ef8119cb3aa 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -4981,8 +4981,21 @@ bool WM_event_handler_region_marker_poll(const wmWindow *win, break; } + /* Check for markers in the current scene, noting that the VSE uses a special sequencer scene. */ + Scene *scene = WM_window_get_active_scene(win); + + if (area->spacetype == SPACE_SEQ) { + WorkSpace *workspace = WM_window_get_active_workspace(win); + if (workspace && workspace->sequencer_scene) { + scene = workspace->sequencer_scene; + } + else { + return false; + } + } + const ListBase *markers = ED_scene_markers_get_from_area( - WM_window_get_active_scene(win), WM_window_get_active_view_layer(win), area); + scene, WM_window_get_active_view_layer(win), area); if (BLI_listbase_is_empty(markers)) { return false; } From a8e64f9a226143f969b94530cd678506cfeec85f Mon Sep 17 00:00:00 2001 From: John Kiril Swenson Date: Thu, 16 Oct 2025 01:55:08 +0200 Subject: [PATCH 2/2] Fix: VSE: Crash from prefetch scene strip infinite recursion PRs #147511 and #147595 ensured that any check for scene strip renders in the prefetch thread would also recurse into "sequencer-type" scene strips, but this introduced the potential for an infinite recursion. Fix by using `SeqRenderState` to detect such a recursion. Also remove unused `seqbasep` context member in `PrefetchJob`, and add a check for non-nullptr `Editing`, fixing a crash where the scene was present without an `Editing` counterpart. Pull Request: https://projects.blender.org/blender/blender/pulls/147949 --- source/blender/sequencer/intern/prefetch.cc | 24 +++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/source/blender/sequencer/intern/prefetch.cc b/source/blender/sequencer/intern/prefetch.cc index c9027356933..df93d4cab5f 100644 --- a/source/blender/sequencer/intern/prefetch.cc +++ b/source/blender/sequencer/intern/prefetch.cc @@ -69,7 +69,6 @@ struct PrefetchJob { /* context */ RenderData context = {}; RenderData context_cpy = {}; - ListBase *seqbasep = nullptr; /* prefetch area */ int cfra = 0; @@ -201,6 +200,7 @@ static int seq_prefetch_cfra(PrefetchJob *pfjob) } return new_frame; } + static AnimationEvalContext seq_prefetch_anim_eval_context(PrefetchJob *pfjob) { return BKE_animsys_eval_context_construct(pfjob->depsgraph, seq_prefetch_cfra(pfjob)); @@ -424,7 +424,8 @@ static bool seq_prefetch_scene_strip_is_rendered(const Scene *scene, ListBase *channels, ListBase *seqbase, blender::Span scene_strips, - int timeline_frame) + int timeline_frame, + SeqRenderState state) { blender::Vector rendered_strips = seq_shown_strips_get( scene, channels, seqbase, timeline_frame, 0); @@ -433,14 +434,21 @@ static bool seq_prefetch_scene_strip_is_rendered(const Scene *scene, for (Strip *strip : rendered_strips) { if (strip->type == STRIP_TYPE_META && seq_prefetch_scene_strip_is_rendered( - scene, &strip->channels, &strip->seqbase, scene_strips, timeline_frame)) + scene, &strip->channels, &strip->seqbase, scene_strips, timeline_frame, state)) { return true; } + /* Recursive "sequencer-type" scene strip detected, no point in attempting to render it. */ + if (state.strips_rendering_seqbase.contains(strip)) { + return true; + } + if (strip->type == STRIP_TYPE_SCENE && (strip->flag & SEQ_SCENE_STRIPS) != 0 && - strip->scene != nullptr) + strip->scene != nullptr && editing_get(strip->scene)) { + state.strips_rendering_seqbase.add(strip); + const Scene *target_scene = strip->scene; const Editing *target_ed = editing_get(target_scene); ListBase *target_seqbase = target_ed->current_strips(); @@ -452,7 +460,8 @@ static bool seq_prefetch_scene_strip_is_rendered(const Scene *scene, target_ed->current_channels(), target_ed->current_strips(), target_scene_strips, - target_timeline_frame); + target_timeline_frame, + state); } /* Check if strip is effect of scene strip or uses it as modifier. @@ -470,9 +479,12 @@ static bool seq_prefetch_scene_strip_is_rendered(const Scene *scene, * make it unresponsive for long time periods. */ static bool seq_prefetch_must_skip_frame(PrefetchJob *pfjob, ListBase *channels, ListBase *seqbase) { + /* Pass in state to check for infinite recursion of "sequencer-type" scene strips. */ + SeqRenderState state = {}; + blender::VectorSet scene_strips = query_scene_strips(seqbase); if (seq_prefetch_scene_strip_is_rendered( - pfjob->scene_eval, channels, seqbase, scene_strips, seq_prefetch_cfra(pfjob))) + pfjob->scene_eval, channels, seqbase, scene_strips, seq_prefetch_cfra(pfjob), state)) { return true; }