Skip to main content

Module morph

Module morph 

Source
Expand description

Render-world half of morphFilter: the freeze (stealing the layer’s on-screen pixels as the “from” snapshot), the per-frame blend pass, and the morph composite gate.

Per frame, for each layer with an extracted morph (ExtractedMorph — an active crate::filters::MorphState plus a resolved single-pass chain):

  1. freeze_morph_snapshot + maintain_morph_blend (called from prepare_layer_textures, bracketing its realloc) maintain the MorphSlot. A new freeze_seq steals the pixels currently on screen — the previous blend (an interrupted morph’s in-flight mix) or the capture texture itself — as snapshot, before the realloc that a same-frame content/size change would trigger drops them. No blit/copy: taking over the texture is free and survives reallocs by construction. Nothing valid to freeze (startup) degrades to no snapshot — the blend becomes a self-blend of the live capture (a visual snap while progress runs, never garbage).
  2. prepare_layer_morphs (PrepareBindGroups, after prepare_layer_textures, before prepare_layer_filters) stages the single blend pass every frame while the morph is in flight (progress moves — the uniforms change even when nothing else does), reusing the content-filter pipeline wholesale: binding 0 = the live capture (the “to”), binding 3 = the snapshot (the “from” — layout-anchored, plain 0..1 UV stretches it onto the current capture rect), target = the dedicated blend texture. The engine writes the reserved params[7].x = progress (see the MORPH CONTRACT in filter_prelude.wgsl).
  3. run_morph_passes (called from ui_layer_capture_pass, after the layer’s capture, before its regular filter run) executes the pass.
  4. The regular filter chain (if any) sources the blend instead of the capture — morph first, then filters; a morph-ONLY layer’s composite quad samples blend directly, gated by morph_gate with the same never-show-partial-content discipline as the content-filter gate.

The blend target is deliberately NOT a prepended ping-pong pass: with a ≥2-pass regular chain, pass 2 would overwrite the blend’s ping-pong slot, and the interrupt freeze (which steals the blended output) would freeze a re-filtered image instead. A dedicated texture keeps the regular chain’s indices untouched and the freeze source well-defined.

Structs§

ExtractedMorph
A layer’s morph, as seen by the render world this frame. Present iff the main-world crate::filters::MorphState is active AND the resolved morph chain has exactly one pass (the resolver’s cap).
MorphMeta
Per-frame morph staging, index-aligned with ExtractedUiLayers::layers. Owns its own uniform buffer (the shared- buffer order-coupling rule — see BackdropMeta).
MorphSlot
A layer’s persistent morph resources: the frozen snapshot (the “from” texture, stolen at freeze) and the dedicated blend target the morph pass writes (what the regular chain — or the composite — samples). Preserved across LayerSlot reallocs (the snapshot must survive a same-frame capture resize on the freeze frame); cleared when the extracted morph disappears (settle, unset, demote).

Functions§

freeze_morph_snapshot
Consume a new freeze_seq: steal the pixels currently on screen as the snapshot and reset the slot’s morph state around it. MUST run before the caller’s realloc branch — the steal reads the pre-realloc textures — and the caller must preserve slot.morph across that realloc.
maintain_morph_blend
Post-realloc maintenance: clear the slot when the morph ended, and track the capture size with the blend target (a mid-flight resize re-allocates the blend only — the snapshot survives untouched).
morph_gate
Whether a morph-ONLY layer’s composite may draw this frame, maintaining the gate-warn bookkeeping. Returns the bind group over blend when ready. Same discipline as the content-filter gate: never fall back to the raw capture (the mid-blend flash this gate exists to prevent).
prepare_layer_morphs
Stage every morphing layer’s blend pass for this frame. Mirrors prepare_layer_filters’ three phases; staging is unconditional per in-flight frame (progress moves every frame). Ordered after prepare_layer_textures (the slot/blend exist) and before prepare_layer_filters (the regular chain’s validity prediction reads MorphSlot::output_valid).
run_morph_passes
Execute one layer’s staged morph pass inside the capture-pass encoder: capture (already rendered) + snapshot → blend. Called per layer from ui_layer_capture_pass, after the capture, before the regular filter replay (which sources the blend).