From 5dbde4cbc43fcebcb83f055c9ed831dbf8a91e5f Mon Sep 17 00:00:00 2001 From: CalamitousFelicitousness Date: Sat, 25 Apr 2026 04:17:27 +0100 Subject: [PATCH] fix(ltx): two-stage refine for Distilled 2.x T2V/I2V auto_refine_upsample gated on supports_canonical_stage2 (Dev-only LoRA path), so Distilled refine ran same-res for both stages and oversaturated. Split the gate: supports_two_stage_refine covers any 2.x non-condition variant and drives the staging plan plus UI Refine default; supports_canonical_stage2 stays Dev-only for the LoRA branch. --- modules/ltx/ltx_capabilities.py | 4 ++++ modules/ltx/ltx_process.py | 8 ++++---- modules/ltx/ltx_ui.py | 8 ++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/modules/ltx/ltx_capabilities.py b/modules/ltx/ltx_capabilities.py index 499f8b57b..83fd5ebed 100644 --- a/modules/ltx/ltx_capabilities.py +++ b/modules/ltx/ltx_capabilities.py @@ -37,6 +37,9 @@ class LTXCaps: modality_default_scale: float = 1.0 guidance_rescale_default: float = 0.0 supports_canonical_stage2: bool = False + # Stage 1 at target/2 -> 2x upsample -> Stage 2 at target. Distilled needs upsampled latents + # for refine; same-res refine oversaturates. Condition variants would need per-stage rebuild. + supports_two_stage_refine: bool = False stage2_dev_lora_repo: Optional[str] = None @@ -121,6 +124,7 @@ def get_caps(model_name: str) -> Optional[LTXCaps]: elif variant == '2.0': caps.stage2_dev_lora_repo = 'CalamitousFelicitousness/LTX-2.0-distilled-lora-384-Diffusers' caps.supports_canonical_stage2 = caps.stage2_dev_lora_repo is not None + caps.supports_two_stage_refine = is_ltx2 and not is_condition_cls if is_ltx2: if variant == '2.3': diff --git a/modules/ltx/ltx_process.py b/modules/ltx/ltx_process.py index 54e5d562e..9c306a089 100644 --- a/modules/ltx/ltx_process.py +++ b/modules/ltx/ltx_process.py @@ -174,13 +174,13 @@ def run_ltx(task_id, return # Lightricks TI2VidTwoStagesPipeline: Stage 1 at half-res, 2x upsample, Stage 2 refine at target. - # Auto-couple when the user picks Refine but not Upsample. Condition variants still need per-stage - # conditioning rebuild, so keep them on the same-resolution path. + # Auto-couple when the user picks Refine but not Upsample. Both Dev and Distilled refine paths + # expect upsampled latents; same-res refine on Distilled produces oversaturation. Condition + # variants still need per-stage conditioning rebuild and are excluded by supports_two_stage_refine. auto_refine_upsample = ( refine_enable - and caps.supports_canonical_stage2 + and caps.supports_two_stage_refine and not upsample_enable - and not caps.supports_multi_condition ) effective_upsample_enable = upsample_enable or auto_refine_upsample effective_upsample_ratio = upsample_ratio if upsample_enable else 2.0 diff --git a/modules/ltx/ltx_ui.py b/modules/ltx/ltx_ui.py index 94bd857ef..896a89cf7 100644 --- a/modules/ltx/ltx_ui.py +++ b/modules/ltx/ltx_ui.py @@ -31,10 +31,10 @@ def _model_change(model_name: str): ) # 2.x refine runs fixed canonical schedules; refine_strength only feeds 0.9.x LTXConditionPipeline. refine_strength_interactive = caps.family == '0.9' - # Default Refine on for Dev 2.x T2V/I2V: Lightricks' production recipe is Stage 1 + 2x upsample - # + Stage 2 refine (auto_refine_upsample at ltx_process.py:179 couples the stages once Refine is on). - # Multi-condition variants are excluded for the same reason auto_refine_upsample excludes them. - refine_default = caps.supports_canonical_stage2 and not caps.supports_multi_condition + # Default Refine on for any 2.x variant whose refine path expects upsampled latents (Dev and + # Distilled T2V/I2V). auto_refine_upsample at ltx_process.py:179 couples the stages once Refine + # is on. Condition variants are excluded by supports_two_stage_refine. + refine_default = caps.supports_two_stage_refine return ( gr.update(visible=caps.supports_input_media), gr.update(visible=caps.supports_multi_condition),