TwoSamplersForMask Upscaler Provider (pipe)
Mask-aware sampling, plugged into Iterative Upscale
- base_sampler
- mask_sampler
- mask
- basic_pipe
- full_sampler_opt
- upscale_model_opt
- pk_hook_base_opt
- pk_hook_mask_opt
- pk_hook_full_opt
- UPSCALER
Impact Pack's Iterative Upscale node needs an "Upscaler" plugged into it to actually do the per-step work - that's the whole architecture: the iterator handles splitting a scale factor into steps, and whatever Upscaler you feed it decides what happens at each step. TwoSamplersForMaskUpscalerProviderPipe is one such Upscaler, and it's specifically the mask-aware one: it extends the pack's TwoSamplersForMask idea (base sampler outside a mask, a different sampler inside it) so that split-region sampling happens at every step of an iterative upscale, not just once.
The "pipe" in the name means it takes a basic_pipe (model, clip, vae, positive, negative bundled together) instead of those five things as separate inputs - the usual Impact Pack convention for keeping upscaler-provider nodes' input lists manageable.
How it works
You give it a basic_pipe, a mask, and two samplers (base_sampler for outside the mask, mask_sampler for inside it - both plain KSAMPLER type here, built with KSamplerProvider). When Iterative Upscale calls this Upscaler at each step, it scales the image with scale_method, then samples the unmasked and masked regions with their respective samplers, same split-region logic as TwoSamplersForMask, repeated at every upscale step instead of once.
full_sample_schedule adds a third option into the mix: at certain steps (controlled by this schedule - options like interleave1, last2, or combinations like interleave2+last1) the node can run a full, non-split sampling pass across the whole image instead of the base/mask split, using full_sampler_opt if you've supplied one. That's useful for occasionally letting the whole image reconcile globally between mask-split steps, rather than the base and mask regions drifting apart across many iterations. use_tiled_vae switches the VAE decode/encode inside each step to a tiled version, trading a little speed for lower VRAM.
The inputs and outputs that matter
basic_pipe(required) - model/clip/vae/positive/negative, bundled.base_sampler/mask_sampler(both KSAMPLER, required) - build withKSamplerProvider. Same split asTwoSamplersForMask: base outside the mask, mask sampler inside it.mask(required) - defines the split.scale_method(nearest-exact/bilinear/lanczos/area) - how each step's resize happens.full_sample_schedule- when (if ever) a whole-image pass runs instead of the split.nonedisables it entirely.tile_size(default 512) anduse_tiled_vae(default false) - VRAM controls for the internal VAE steps.- Optional:
full_sampler_opt(needed iffull_sample_scheduleisn'tnone),upscale_model_opt(an ESRGAN-family model for the resize step instead of plain interpolation), and up to threepk_hookslots (pk_hook_base_opt,pk_hook_mask_opt,pk_hook_full_opt) for attachingPK_HOOKbehaviors - a CFG schedule, a denoise schedule - to each of the three sampling paths independently.
Output is a single UPSCALER - not an image or latent. This node builds a plugin; you wire that UPSCALER output into Iterative Upscale (Latent/on Pixel Space) or Iterative Upscale (Image), which is what actually runs the loop and produces your final result.
How to install it
Via ComfyUI Manager: search ComfyUI Impact Pack, install, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/ltdrdata/ComfyUI-Impact-Pack comfyui-impact-pack
cd comfyui-impact-pack
python -m pip install -r requirements.txt # ComfyUI's python; python_embeded on portable
then restart. If you plan to use upscale_model_opt, grab an ESRGAN-family model into ComfyUI/models/upscale_models separately - it's not bundled.
Common issues & troubleshooting
Nothing happens when I connect this node alone. By design - it only produces an UPSCALER plugin object, not an image. You must feed that output into an Iterative Upscale node, which is the one that actually loops and samples.
Set full_sample_schedule but nothing full-frame happens. Check that full_sampler_opt is actually connected - the schedule only fires a full-image pass if you've supplied a sampler for it. Leaving the schedule set but the optional sampler empty means those scheduled steps have nothing to run.
Base and mask regions look inconsistent after several iterations. This is exactly the failure mode full_sample_schedule exists to counter - long runs of pure base/mask split sampling can let the two areas drift apart tonally over many steps. Add a full_sampler_opt and a schedule like interleave2+last1 to periodically reconcile the whole frame.
Ran out of VRAM on a large iterative upscale. Turn on use_tiled_vae and/or lower tile_size. This node is doing real sampling work at every step of the upscale, so it's heavier than a plain interpolation-only upscaler by design.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| scale_method | COMBO | 4 options: nearest-exact, bilinear, lanczos, area | |
| full_sample_schedule | COMBO | 9 options: none, interleave1, interleave2, interleave3, last1, last2, +3 | |
| use_tiled_vae | BOOLEAN | false | — |
| base_sampler | KSAMPLER | — | |
| mask_sampler | KSAMPLER | — | |
| mask | MASK | — | |
| basic_pipe | BASIC_PIPE | — | |
| tile_size | INT | 512320–4096 | — |
| full_sampler_optopt | KSAMPLER | — | |
| upscale_model_optopt | UPSCALE_MODEL | — | |
| pk_hook_base_optopt | PK_HOOK | — | |
| pk_hook_mask_optopt | PK_HOOK | — | |
| pk_hook_full_optopt | PK_HOOK | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| UPSCALER | UPSCALER | — |