ComfyUI Node

Tile Test: Render

Render — Re-Roll One Tile, Not the Whole 8K Canvas

By Blakeem·Created 3 months ago·Updated 9 days ago· 28
Tile Test: Render
  • image
  • layout
  • model
  • clip
  • vae
  • captions
  • negative
  • tiles
  • blocks
◄seed0►
◄sampler_namedpmpp_2m►
◄schedulersgm_uniform►
◄steps20►
◄cfg3.5►
◄denoise0.50►
◄anchor_sourcesource image►
◄surfacevision tokens and captions►
◄canvas_tokens165►
◄crop_tokens165►
◄tiles►
◄with_neighborstrue►

Everything above this node is cached. The layout is solved, the canvas is upscaled, the tile texts are written. Tile Test: Render is where the diffusion happens, and since it's the only node in the chain holding a seed, it's the only one you re-run for a different result.

That's the whole design. A 24-tile 8K refine is minutes of GPU time, and finding out tile 17 has a weird hand shouldn't cost you the other 23. Name tile 17, change the seed, re-run.

The engine underneath

Worth knowing, because it isn't what Ultimate SD Upscale does. The VL nodes keep the entire image in one shared canvas latent, diffuse every tile one step at a time, and between steps consolidate the tiles back into that canvas - the overlap bands cross-dissolved in latent space by the same directional feather the base node applies in pixel space. Each tile runs its own sampler, but all of them are held to one schedule, which is why the sampler list is restricted.

MultiDiffusion and Mixture of Diffusers also touch every tile on every step, but they average the overlapping predictions, and averaging disagreements gives you a soft blend. Here only the thin shared band gets predicted twice.

Inputs

The wiring is the chain you already built: image from Tile Test: Upscale, layout from Tile Test: Layout, plus model, clip and vae. clip carries the same constraint as the Captions node - a vision-language encoder from the Krea 2 family. There's no positive prompt input at all, because every tile's positive is built from the image.

Then seed, sampler_name, scheduler, steps, cfg, denoise. Respect denoise: at 0 it hands the image back unrefined, and the README's own samples sit around 0.35.

anchor_source is the setting with a real personality. source image (default) fills the context ring with the unmodified input, locking placement and style to what you started with - flaws included. live canvas uses neighbors' in-progress results instead, so the refine can repair flawed content; expect more invention and slightly brighter output. If you get drift you didn't ask for, flip this back first.

surface picks what fills each tile's positive: vision tokens, vision tokens and captions, or captions. The combined one is the default and the one to use - tokens keep the tile faithful and at the right scale, the text names what's there. Both caption surfaces need Tile Test: Captions connected.

canvas_tokens and crop_tokens (165 each) are how many vision rows a tile takes from the whole-image encode and from its own crop; zero turns a source off. Tile Test: Settings will hand you these.

Then the two control widgets. tiles is comma-separated tile numbers as the overlay labels them; empty means a full run over the entire canvas. with_neighbors (on) renders the named tile with its bordering tiles as lanes of one run, which is what a full run does. Turn it off and the tile renders alone - and its anchor ring then stays unrefined source, because no neighbor lane is refining it. Optional inputs are captions and negative.

Outputs

Two, both image lists. tiles is one image per named tile, the canvas cut at that tile's crop rect. blocks is the refined block rendered for each named tile - spanning its neighbours when with_neighbors is on, so it's the one to judge seams with. With an empty tiles input, both are the entire refined canvas.

The sampler restriction isn't arbitrary

The synchronized engine has to time every sampler's model evaluations, because all tiles share one schedule. Eleven are supported: euler, heun, dpm_2, dpmpp_2m, the four dpmpp_2m_sde variants, and the two exp_heun_2_x0 ones.

Anything else is rejected before sampling starts. dpm_fast, dpm_adaptive and uni_pc are unsupported by design - they own their own schedule or internal history, so no evals-per-step figure can time them. uni_pc is a common pick on distilled models, so this one bites. The upside: the rejection is caught at queue time, before the encoder and model load.

Installing

ComfyUI Manager → search "Context-Anchored Tile Refine". Or:

cd ComfyUI/custom_nodes
git clone https://github.com/Blakeem/ComfyUI-ContextAnchoredTileRefine
cd ComfyUI-ContextAnchoredTileRefine
pip install -r requirements.txt
cp settings.toml settings.user.toml

One dependency, logit-classifier>=0.4.0. Restart after. You also need the Krea 2 stack - the diffusion model, the Qwen3-VL text encoder (~8GB) and the Qwen-Image VAE.

Where it goes wrong

"renders one picture at a time." Batch size one, like every node in this pack.

A size mismatch. This node wants the exact canvas Tile Test: Upscale returned. A visually identical image resized by one pixel gets rejected.

Caption surfaces with nothing wired into captions. Setting surface to either caption option and leaving the input empty stops the run - the wiring mistake people make when swapping surfaces to compare.

And the one that looks like a crash: a syntax error in the settings file makes this node vanish from the menu, with the reason printed to the console. Fix the TOML, restart, it's back.

Categoryimage/upscaling/tile testing

Inputs (19)

NameTypeDefaultDescription
imageIMAGEThe canvas from Tile Test: Upscale, at the layout's target size.
layoutCATR_LAYOUTThe layout from Tile Test: Layout. Every rect this node samples is read from it.
modelMODELThe diffusion model that denoises each tile.
clipCLIPMust be a vision-language text encoder (Krea 2 family). There is no positive prompt input, since each tile is conditioned on the image itself.
vaeVAEThe VAE that encodes and decodes each tile.
seedINT00–18446744073709550000Noise is drawn once for the entire image and then sliced for each tile.
sampler_nameCOMBOdpmpp_2mThe synchronized tile engine supports these samplers: euler, dpmpp_2m, heun, dpm_2, exp_heun_2_x0, dpmpp_2m_sde, dpmpp_2m_sde_gpu, dpmpp_2m_sde_heun, dpmpp_2m_sde_heun_gpu, exp_heun_2_x0_sde. Any other sampler is rejected.
schedulerCOMBOsgm_uniformHow the noise levels are spaced across the steps.
stepsINT201–10000The number of sampling steps each tile runs at any denoise value.
cfgFLOAT3.50–100How strongly each tile follows its positive conditioning over the negative.
denoiseFLOAT0.500–1The fraction of the noise schedule each tile runs, where 0 samples nothing and returns the image unrefined.
anchor_sourceCOMBOsource imageWhat fills context_anchor. source image keeps the result true to the input. live canvas adds more detail and drifts further from the input.
surfaceCOMBOvision tokens and captionsWhat fills every tile's positive. The two caption surfaces need Tile Test: Captions connected. The VL nodes use the vision tokens and captions surface by default.
canvas_tokensINT1650–1953Vision rows a tile takes from one encode of the entire image. 0 turns that source off.
crop_tokensINT1650–1953Vision rows a tile takes from the encode of its own crop. 0 turns that source off.
tilesSTRINGComma separated tile numbers, as Tile Test: Layout labels them. Empty renders the entire canvas as one run.
with_neighborsBOOLEANtrueOn renders the tile with its bordering tiles as lanes of one run, which is what the full run does. Off renders the tile alone, and its anchor ring then stays unrefined source, since no neighbour lane refines it.
captionsoptCATR_CAPTIONSThe captions from Tile Test: Captions. The two caption surfaces need them and the vision tokens surface ignores them.
negativeoptCONDITIONINGOptional negative conditioning. Unconnected it is an empty encode of this node's CLIP.

Outputs (2)

NameTypeDescription
tilesIMAGEOne image per named tile, the refined canvas cut at the tile's crop rect. An empty tiles input returns the entire refined canvas.
blocksIMAGEOne image per named tile, the refined block rendered for it, which spans its bordering tiles when with_neighbors is on. An empty tiles input returns the entire refined canvas.