Nodes/ComfyUI-OCIO/OCIO VAE Decode
ComfyUI Node

OCIO VAE Decode

Your VAE decode clamps. This one doesn't — and for HDR that's the whole ballgame

By SlavaSexton·Created 2 months ago·Updated 3 days ago· 99
OCIO VAE Decode
  • samples
  • vae
  • image/sequence/video
  • range report
precisionfloat32
clampfalse
tiledtrue
tile_size384
overlap64
temporal_size4096
temporal_overlap32

The stock VAEDecode ends with .clamp_(0, 1). That's correct for an 8-bit preview and quietly destructive for anything else: on an HDR decode, every value above white and below black is gone - mapped to exactly 1.0 and 0.0, a projection onto the boundary that no float container downstream can undo, because the range never reached the tensor. OCIO VAE Decode is that node with the clamp off, optionally run in float32, with spatial tiling for long clips and a range report so you can read the damage before you commit. With clamp turned back on, it reproduces stock VAEDecode bit for bit - so it's a safe drop-in either way.

But read the honesty in the node's own description before you get excited: on an ordinary SDR generation the clamp costs 0.06% of samples. On real ACEScct HDR material carrying +3.9 stops it costs nothing at all, because 15x white only reaches code 0.80 - the clamp only bites above code 1.0, i.e. linear past ~222. This is for control over the decode, not a rescue for dynamic range the model never produced. The measured numbers tell both stories: one LTX-2.5 frame decoded unclamped showed 78% of samples below zero (the ACEScct codes live low), while an SDR frame had a handful of outliers either way.

The inputs that matter

  • samples + vae - exactly what stock VAEDecode takes.
  • precision - float32 (default) or float16. Float32 is the expensive one: ~5x the model's own dtype on the decode. Float16 only applies where the VAE lists it - the LTX video VAE doesn't, so the node declines and tells you on the report.
  • clamp - off by default. On, it's stock, for comparison. Falsifiable in one toggle.
  • tiled / tile_size / overlap - spatial tiling, on by default since v1.3.0: the untiled path is the one that OOMs on a real clip. If a decode crawls, lower tile_size first (384 default).
  • temporal_size / temporal_overlap - and here's the rule the tooltip shouts: tile SPACE, never TIME. Leave temporal_size at its 4096 default (which makes the whole clip one temporal tile); lowering it puts a visibly soft frame at a fixed period, because a diffusion decoder has no context at a temporal tile edge. A wider overlap spreads the weak edge, it doesn't fix it.

Outputs: the decoded frames (image/sequence/video, unclamped unless you asked otherwise - what the values mean depends on how the generation encoded them: display RGB for SDR, ACEScct log codes on LTX-2's HDR path) and a range report STRING with min/max/mean, percentiles, and the exact share of samples below 0 and above 1 - the range the stock clamp would have destroyed.

The LTX-2.5 recipe, short version

Decode with clamp off and precision float32, read the range report to see what you saved, then OCIO LogConvert (Log to Linear, curve ACEScct), OCIO ColorSpace to ACEScg, OCIO Write as EXR 16f. That chain is the whole reason this node exists. Install via Manager (Nightly - the numbered registry entries are stale/flagged) or clone https://github.com/SlavaSexton/ComfyUI-OCIO and pip install -r requirements.txt. No model files to fetch; it needs the VAE you already have. If a long decode OOMs, tiling is on - check tile_size, not the temporal fields.

CategoryOCIO

Inputs (9)

NameTypeDefaultDescription
samplesLATENTThe latent to decode, same input the stock VAE Decode takes.
vaeVAEThe VAE that belongs to the model. A VAE is trained together with its transformer and cannot be swapped for another one.
precisionCOMBOfloat32float32 is the default and costs 5.2x the model's own dtype: 28.8 s against 5.5 s, 25 frames at 1280x704 tiled 384. float16 applies only where the VAE lists it; LTX does not, so it falls back and the report says so. docs/NODES_VAE.md 3.2.
clampBOOLEANfalseOFF (default) passes values through as the model produced them, including anything below 0 or above 1. ON reproduces the stock VAE Decode exactly - use it only to compare against the standard path.
tiledoptBOOLEANtrueDecode in tiles. ON by default since v1.3.0: the untiled path is the one that runs out of memory on a real clip, and it is slower even when it fits - 121 frames at float32 took 912 s untiled against 60 s tiled. Tiling does change the picture, by roughly 30x what precision does, so turn it off for a short clip where the whole frame fits. docs/NODES_VAE.md 3.3.
tile_sizeoptINT38464–4096Spatial tile in PIXELS, divided by the VAE's compression ratio (32x on LTX, so 384 becomes 12). 384 measured clean at 60 s for 121 frames; 768 overflowed. If a decode crawls, lower this first. docs/NODES_VAE.md 3.3.
overlapoptINT640–4096Spatial overlap between tiles in PIXELS, feathered by the blend. Held to a quarter of the tile, ComfyUI's own convention (comfy/sd.py:1234). Spatial seams are not the problem: measured gradient excess is 1.03-1.05x.
temporal_sizeoptINT40968–4096TILE SPACE, NEVER TIME. The 4096 default exceeds any clip on purpose, making the whole sequence one temporal tile so no time tiling happens. Lowering it leaves a visibly soft frame at a fixed period. docs/NODES_VAE.md 3.3.
temporal_overlapoptINT324–4096Temporal overlap in PIXEL frames, used only when temporal_size is small enough to split the clip. Held to half the temporal tile. It cannot repair the soft frame: a wider blend spreads the weak edge over more frames instead of removing it.

Outputs (2)

NameTypeDescription
image/sequence/videoIMAGEThe decoded frames, unclamped unless you asked otherwise. What the values MEAN depends on how the generation encoded them: display RGB for SDR, ACEScct log codes on LTX-2's HDR path.
range reportSTRINGmin, max, mean, percentiles, and the exact share of samples below 0 and above 1 - the range the standard clamp would have destroyed. Also carries a note for anything the node declined to do, which would otherwise reach the server log only.