Fix #146484: Stack overflow due to recursive strip rendering
When effect of adjustment layer strip is moved below the adjustment layer, this causes infinite loop in strip rendering. Same happens when you use multicam strip and set source channel to one of its effects. This is fixed by passing `SeqRenderState` to the effects. If any strip renders "seqbase" pointer of strip is stored in set in the render state struct. If the pointer exists in this set, function returns without rendering anything. In other words, The strip must never render itself. Pull Request: https://projects.blender.org/blender/blender/pulls/146624
This commit is contained in:
committed by
Richard Antalik
parent
84559f8bd4
commit
97297bd167
@@ -20,6 +20,7 @@ struct TextVars;
|
||||
|
||||
namespace blender::seq {
|
||||
|
||||
struct SeqRenderState;
|
||||
struct RenderData;
|
||||
|
||||
enum class StripEarlyOut {
|
||||
@@ -58,6 +59,7 @@ struct EffectHandle {
|
||||
|
||||
/* execute the effect */
|
||||
ImBuf *(*execute)(const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
Strip *strip,
|
||||
float timeline_frame,
|
||||
float fac,
|
||||
|
||||
@@ -47,6 +47,7 @@ struct AddEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_add_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip * /*seq*/,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
@@ -91,6 +92,7 @@ struct SubEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_sub_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip * /*seq*/,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
@@ -135,6 +137,7 @@ struct MulEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_mul_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip * /*seq*/,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
|
||||
@@ -31,7 +31,10 @@ static StripEarlyOut early_out_adjustment(const Strip * /*strip*/, float /*fac*/
|
||||
return StripEarlyOut::NoInput;
|
||||
}
|
||||
|
||||
static ImBuf *do_adjustment_impl(const RenderData *context, Strip *strip, float timeline_frame)
|
||||
static ImBuf *do_adjustment_impl(const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
Strip *strip,
|
||||
float timeline_frame)
|
||||
{
|
||||
Editing *ed;
|
||||
ImBuf *i = nullptr;
|
||||
@@ -50,7 +53,7 @@ static ImBuf *do_adjustment_impl(const RenderData *context, Strip *strip, float
|
||||
|
||||
if (strip->channel > 1) {
|
||||
i = seq_render_give_ibuf_seqbase(
|
||||
context, timeline_frame, strip->channel - 1, channels, seqbasep);
|
||||
context, state, timeline_frame, strip->channel - 1, channels, seqbasep);
|
||||
}
|
||||
|
||||
/* Found nothing? so let's work the way up the meta-strip stack, so
|
||||
@@ -63,7 +66,7 @@ static ImBuf *do_adjustment_impl(const RenderData *context, Strip *strip, float
|
||||
meta = lookup_meta_by_strip(ed, strip);
|
||||
|
||||
if (meta) {
|
||||
i = do_adjustment_impl(context, meta, timeline_frame);
|
||||
i = do_adjustment_impl(context, state, meta, timeline_frame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +74,7 @@ static ImBuf *do_adjustment_impl(const RenderData *context, Strip *strip, float
|
||||
}
|
||||
|
||||
static ImBuf *do_adjustment(const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
Strip *strip,
|
||||
float timeline_frame,
|
||||
float /*fac*/,
|
||||
@@ -82,11 +86,12 @@ static ImBuf *do_adjustment(const RenderData *context,
|
||||
|
||||
ed = context->scene->ed;
|
||||
|
||||
if (!ed) {
|
||||
if (!ed || state->strips_rendering_seqbase.contains(strip)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
out = do_adjustment_impl(context, strip, timeline_frame);
|
||||
state->strips_rendering_seqbase.add(strip);
|
||||
out = do_adjustment_impl(context, state, strip, timeline_frame);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ struct AlphaOverEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_alphaover_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip * /*strip*/,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
@@ -125,6 +126,7 @@ struct AlphaUnderEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_alphaunder_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip * /*strip*/,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
@@ -325,6 +327,7 @@ struct BlendModeEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_blend_mode_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
@@ -356,6 +359,7 @@ static void init_colormix_effect(Strip *strip)
|
||||
}
|
||||
|
||||
static ImBuf *do_colormix_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float /*fac*/,
|
||||
|
||||
@@ -45,6 +45,7 @@ struct CrossEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_cross_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip * /*seq*/,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
@@ -98,6 +99,7 @@ struct GammaCrossEffectOp {
|
||||
};
|
||||
|
||||
static ImBuf *do_gammacross_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip * /*seq*/,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
|
||||
@@ -139,6 +139,7 @@ static void gaussian_blur_y(const Span<float> gaussian,
|
||||
}
|
||||
|
||||
static ImBuf *do_gaussian_blur_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float /*fac*/,
|
||||
|
||||
@@ -224,6 +224,7 @@ static void do_glow_effect_float(Strip *strip,
|
||||
}
|
||||
|
||||
static ImBuf *do_glow_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
|
||||
@@ -30,6 +30,7 @@ static StripEarlyOut early_out_multicam(const Strip * /*strip*/, float /*fac*/)
|
||||
}
|
||||
|
||||
static ImBuf *do_multicam(const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
Strip *strip,
|
||||
float timeline_frame,
|
||||
float /*fac*/,
|
||||
@@ -44,7 +45,7 @@ static ImBuf *do_multicam(const RenderData *context,
|
||||
}
|
||||
|
||||
ed = context->scene->ed;
|
||||
if (!ed) {
|
||||
if (!ed || state->strips_rendering_seqbase.contains(strip)) {
|
||||
return nullptr;
|
||||
}
|
||||
ListBase *seqbasep = get_seqbase_by_strip(context->scene, strip);
|
||||
@@ -53,8 +54,9 @@ static ImBuf *do_multicam(const RenderData *context,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
state->strips_rendering_seqbase.add(strip);
|
||||
out = seq_render_give_ibuf_seqbase(
|
||||
context, timeline_frame, strip->multicam_source, channels, seqbasep);
|
||||
context, state, timeline_frame, strip->multicam_source, channels, seqbasep);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ static StripEarlyOut early_out_color(const Strip * /*strip*/, float /*fac*/)
|
||||
}
|
||||
|
||||
static ImBuf *do_solid_color(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float /*fac*/,
|
||||
|
||||
@@ -184,6 +184,7 @@ static float speed_effect_interpolation_ratio_get(Scene *scene,
|
||||
}
|
||||
|
||||
static ImBuf *do_speed_effect(const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
Strip *strip,
|
||||
float timeline_frame,
|
||||
float fac,
|
||||
@@ -197,7 +198,7 @@ static ImBuf *do_speed_effect(const RenderData *context,
|
||||
if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
|
||||
fac = speed_effect_interpolation_ratio_get(context->scene, strip, timeline_frame);
|
||||
/* Current frame is ibuf1, next frame is ibuf2. */
|
||||
out = cross_effect.execute(context, nullptr, timeline_frame, fac, ibuf1, ibuf2);
|
||||
out = cross_effect.execute(context, state, nullptr, timeline_frame, fac, ibuf1, ibuf2);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -1021,6 +1021,7 @@ TextVarsRuntime *text_effect_calc_runtime(const Strip *strip, int font, const in
|
||||
}
|
||||
|
||||
static ImBuf *do_text_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float /*fac*/,
|
||||
|
||||
@@ -130,6 +130,7 @@ static void transform_image(int x,
|
||||
}
|
||||
|
||||
static ImBuf *do_transform_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float /*fac*/,
|
||||
|
||||
@@ -354,6 +354,7 @@ static void do_wipe_effect(
|
||||
}
|
||||
|
||||
static ImBuf *do_wipe_effect(const RenderData *context,
|
||||
SeqRenderState * /*state*/,
|
||||
Strip *strip,
|
||||
float /*timeline_frame*/,
|
||||
float fac,
|
||||
|
||||
@@ -770,7 +770,7 @@ static ImBuf *seq_render_effect_strip_impl(const RenderData *context,
|
||||
|
||||
switch (early_out) {
|
||||
case StripEarlyOut::NoInput:
|
||||
out = sh.execute(context, strip, timeline_frame, fac, nullptr, nullptr);
|
||||
out = sh.execute(context, state, strip, timeline_frame, fac, nullptr, nullptr);
|
||||
break;
|
||||
case StripEarlyOut::DoEffect:
|
||||
for (i = 0; i < 2; i++) {
|
||||
@@ -795,7 +795,7 @@ static ImBuf *seq_render_effect_strip_impl(const RenderData *context,
|
||||
}
|
||||
|
||||
if (ibuf[0] && (ibuf[1] || effect_get_num_inputs(strip->type) == 1)) {
|
||||
out = sh.execute(context, strip, timeline_frame, fac, ibuf[0], ibuf[1]);
|
||||
out = sh.execute(context, state, strip, timeline_frame, fac, ibuf[0], ibuf[1]);
|
||||
}
|
||||
break;
|
||||
case StripEarlyOut::UseInput1:
|
||||
@@ -1789,7 +1789,13 @@ static StripEarlyOut strip_get_early_out_for_blend_mode(Strip *strip)
|
||||
}
|
||||
|
||||
static ImBuf *seq_render_strip_stack_apply_effect(
|
||||
const RenderData *context, Strip *strip, float timeline_frame, ImBuf *ibuf1, ImBuf *ibuf2)
|
||||
|
||||
const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
Strip *strip,
|
||||
float timeline_frame,
|
||||
ImBuf *ibuf1,
|
||||
ImBuf *ibuf2)
|
||||
{
|
||||
ImBuf *out;
|
||||
EffectHandle sh = strip_blend_mode_handle_get(strip);
|
||||
@@ -1798,10 +1804,10 @@ static ImBuf *seq_render_strip_stack_apply_effect(
|
||||
int swap_input = seq_must_swap_input_in_blend_mode(strip);
|
||||
|
||||
if (swap_input) {
|
||||
out = sh.execute(context, strip, timeline_frame, fac, ibuf2, ibuf1);
|
||||
out = sh.execute(context, state, strip, timeline_frame, fac, ibuf2, ibuf1);
|
||||
}
|
||||
else {
|
||||
out = sh.execute(context, strip, timeline_frame, fac, ibuf1, ibuf2);
|
||||
out = sh.execute(context, state, strip, timeline_frame, fac, ibuf1, ibuf2);
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -1911,7 +1917,8 @@ static ImBuf *seq_render_strip_stack(const RenderData *context,
|
||||
context->rectx, context->recty, 32, use_float ? IB_float_data : IB_byte_data);
|
||||
seq_imbuf_assign_spaces(context->scene, ibuf1);
|
||||
|
||||
out = seq_render_strip_stack_apply_effect(context, strip, timeline_frame, ibuf1, ibuf2);
|
||||
out = seq_render_strip_stack_apply_effect(
|
||||
context, state, strip, timeline_frame, ibuf1, ibuf2);
|
||||
IMB_metadata_copy(out, ibuf2);
|
||||
|
||||
intra_frame_cache_put_composite(context->scene, strip, out);
|
||||
@@ -1939,7 +1946,8 @@ static ImBuf *seq_render_strip_stack(const RenderData *context,
|
||||
ImBuf *ibuf1 = out;
|
||||
ImBuf *ibuf2 = seq_render_strip(context, state, strip, timeline_frame);
|
||||
|
||||
out = seq_render_strip_stack_apply_effect(context, strip, timeline_frame, ibuf1, ibuf2);
|
||||
out = seq_render_strip_stack_apply_effect(
|
||||
context, state, strip, timeline_frame, ibuf1, ibuf2);
|
||||
|
||||
IMB_freeImBuf(ibuf1);
|
||||
IMB_freeImBuf(ibuf2);
|
||||
@@ -2013,14 +2021,14 @@ ImBuf *render_give_ibuf(const RenderData *context, float timeline_frame, int cha
|
||||
}
|
||||
|
||||
ImBuf *seq_render_give_ibuf_seqbase(const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
float timeline_frame,
|
||||
int chan_shown,
|
||||
ListBase *channels,
|
||||
ListBase *seqbasep)
|
||||
{
|
||||
SeqRenderState state;
|
||||
|
||||
return seq_render_strip_stack(context, &state, channels, seqbasep, timeline_frame, chan_shown);
|
||||
return seq_render_strip_stack(context, state, channels, seqbasep, timeline_frame, chan_shown);
|
||||
}
|
||||
|
||||
ImBuf *render_give_ibuf_direct(const RenderData *context, float timeline_frame, Strip *strip)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
struct ImBuf;
|
||||
@@ -24,6 +25,7 @@ namespace blender::seq {
|
||||
/* Mutable state while rendering one sequencer frame. */
|
||||
struct SeqRenderState {
|
||||
LinkNode *scene_parents = nullptr;
|
||||
Set<Strip *> strips_rendering_seqbase;
|
||||
};
|
||||
|
||||
/* Strip corner coordinates in screen pixel space. Note that they might not be
|
||||
@@ -38,6 +40,7 @@ struct StripScreenQuad {
|
||||
};
|
||||
|
||||
ImBuf *seq_render_give_ibuf_seqbase(const RenderData *context,
|
||||
SeqRenderState *state,
|
||||
float timeline_frame,
|
||||
int chan_shown,
|
||||
ListBase *channels,
|
||||
|
||||
BIN
tests/files/sequence_editing/effects/recursive_render_crash_146484.blend
(Stored with Git LFS)
Normal file
BIN
tests/files/sequence_editing/effects/recursive_render_crash_146484.blend
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
tests/files/sequence_editing/effects/reference/recursive_render_crash_146484.png
(Stored with Git LFS)
Normal file
BIN
tests/files/sequence_editing/effects/reference/recursive_render_crash_146484.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Reference in New Issue
Block a user