Render: ask the effect spec whether a stack can skip the layer cover

Matej's follow-up kept the known-margin set as SKIPS_COVER and the renderer looked the ids up. Ask EffectSpec::skips_cover instead so a new margin effect opts in on the spec rather than in run_effect_stack. Tests pin align_plan to cover_shift mod 64 and that Twirl still takes the full cover.
This commit is contained in:
Vikram Bhaskaran
2026-10-14 12:14:27 +11:00
parent 9a202b133a
commit b51c91a126
2 changed files with 31 additions and 4 deletions
+29
View File
@@ -514,6 +514,15 @@ pub struct EffectSpec {
pub float: bool,
}
impl EffectSpec {
/// True when this effect grows its own buffer (blur/glow margins, Repeat Edge
/// [`Buf::cover`], displacement [`cover_pad`]) so a stack of only these can skip the
/// renderer's full-layer cover and keep the pyramid grid phase (#1205).
pub fn skips_cover(&self) -> bool {
SKIPS_COVER.contains(&self.id)
}
}
pub(crate) fn p(id: &'static str, name: &'static str, default: Value, ui: ParamUi) -> ParamSpec {
ParamSpec { id, name, default, ui }
}
@@ -1504,4 +1513,24 @@ mod tests {
assert_eq!(g.get("noiseSourceLayerSource").map(|p| p.value.clone()), Some(Value::Enum(0)));
assert_eq!(g.props().filter(|p| p.match_id == "noiseSourceLayerSource").count(), 1);
}
#[test]
fn align_plan_is_cover_shift_mod_grid() {
// Content inset from the layer origin: pixel 0 maps to layer (50, 30).
let offset = [-50.0, -30.0];
let scale = 1.0;
let size = [1920.0, 1080.0];
let (dx, dy, _, _) = cover_plan(offset, scale, size, 80, 40).unwrap();
assert_eq!((dx, dy), (50, 30));
assert_eq!(align_plan(offset, scale, size, 80, 40), Some((50, 30)));
assert_eq!(align_plan([-64.0, -128.0], 1.0, size, 80, 40), None);
}
#[test]
fn known_margin_effects_skip_cover_and_twirl_does_not() {
for id in SKIPS_COVER {
assert!(find(id).expect(id).skips_cover(), "{id}");
}
assert!(!find("ec.distort.twirl").unwrap().skips_cover());
}
}
+2 -4
View File
@@ -1150,14 +1150,12 @@ impl<'a> Renderer<'a> {
// get the cover: they move content past the painted bounds without growing the buffer.
let video = || {
fx.groups().filter(|g| g.enabled).filter_map(|g| match &g.kind {
GroupKind::Effect { effect } if effectcraft_effects::find(effect).is_some_and(|s| !effectcraft_effects::audio_fx::is_audio_effect(s.id)) => {
Some(effect.as_str())
}
GroupKind::Effect { effect } => effectcraft_effects::find(effect).filter(|s| !effectcraft_effects::audio_fx::is_audio_effect(s.id)),
_ => None,
})
};
if !adjustment && video().next().is_some() {
if video().all(|id| effectcraft_effects::SKIPS_COVER.contains(&id)) {
if video().all(|s| s.skips_cover()) {
target.align(layer_size);
} else {
target.cover(layer_size);