TwoSamplersForMask Upscaler Provider
Mask-split sampling, plugged into Iterative Upscale
- base_sampler
- mask_sampler
- mask
- vae
- full_sampler_opt
- upscale_model_opt
- pk_hook_base_opt
- pk_hook_mask_opt
- pk_hook_full_opt
- UPSCALER
The mask-aware Upscaler for Iterative Upscale: it extends TwoSamplersForMask's split-region idea - a base sampler outside the mask, a different sampler inside it - so that split-region sampling happens at every step of an iterative upscale, not just once. Per the README, "This is an Upscaler that extends TwoSamplersForMask to be used in Iterative Upscale."
Unlike the pack's basic_pipe-based upscaler providers, this one only needs a vae on top of its two samplers - model, positive and negative are already bundled inside the KSAMPLER objects you build with KSamplerProvider, so there's nothing separate left to supply.
How it works
You give it a vae, a mask, and two KSAMPLERs (base_sampler for outside the mask, mask_sampler for inside it). 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 as TwoSamplersForMask, repeated at every upscale step instead of once.
full_sample_schedule adds a third mode: at certain steps (controlled by the schedule - options like interleave1, last2, or combinations like interleave2+last1) the node runs a full, non-split sampling pass across the whole image instead, using full_sampler_opt if supplied. That's useful for letting the whole image reconcile globally between mask-split steps, so the base and mask regions don't drift apart tonally across many iterations. use_tiled_vae swaps the VAE decode/encode for a tiled version inside each step, trading a little speed for lower VRAM.
The inputs and outputs that matter
vae(required) - used for the internal decode/upscale/encode round-trip at each step.base_sampler/mask_sampler(both KSAMPLER, required) - build withKSamplerProvider(orTiledKSamplerProviderfor a tiled sampler on either side). 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.use_tiled_vae(default false) andtile_size(default 512) - 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), and up to threepk_hookslots (pk_hook_base_opt,pk_hook_mask_opt,pk_hook_full_opt) for attaching separatePK_HOOKbehaviors - a CFG schedule, a denoise schedule - to each of the three sampling paths independently.
Output is a single UPSCALER - a plugin, not an image. Wire it into Iterative Upscale (Latent/on Pixel Space) or Iterative Upscale (Image).
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 either sampler is a TiledKSamplerProvider, you'll also need BlenderNeko/ComfyUI_TiledKSampler - not required if you're using plain KSamplerProviders. For upscale_model_opt, grab an ESRGAN-family model into ComfyUI/models/upscale_models, separately from the base pack install.
Common issues & troubleshooting
Nothing happens when connected alone. By design - this only produces an UPSCALER plugin. Feed the output into an Iterative Upscale node, which actually loops and samples.
Set full_sample_schedule but no full-frame pass fires. Check that full_sampler_opt is actually connected - the schedule only fires a full-image pass if you've supplied a sampler for it.
Base and mask regions drift apart after several iterations. That's exactly what full_sample_schedule exists to counter. Add 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 does real sampling at every step, so it's heavier than a plain interpolation-only upscaler by design.
Do you need this over the pipe version, TwoSamplersForMaskUpscalerProviderPipe? They're functionally equivalent - the difference is purely how model/positive/negative get supplied. This one skips a basic_pipe because those three already live inside your two KSAMPLER objects; the pipe version wants them bundled separately. Use whichever matches what's already in your graph.
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 | — | |
| vae | VAE | — | |
| 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 | — |