The round-1 device canvas disengaged past its fixed 1 GiB budget, so at
final_upscale_factor=4 (~44 MB/frame at 720p) typical clips fell back to
the host assembly at 16x the pixels. The engagement is now three-way:
- device_canvas_budget: a share of the free VRAM (0.25) under the hard
cap, the cap when free memory is unavailable - the mirror of
paste_chunk_size.
- device_output_mode: full | chunked | host. The chunked mode assembles
frame groups on the device (the same group size the full mode derives
internally, so the batch compositions coincide) and downloads the
per-group convert-outs into one preallocated host IMAGE buffer - the
device footprint stays bounded for any clip length.
- comfy_convert_out: the BGR->RGB float convert-out runs on the device
in budget-sized sub-chunks (the out-of-place chain peaks at ~9x the
canvas bytes of transient), so the budget bounds what it gates.
- a "host" verdict on a CUDA device is logged - the silent fallback
that hid the regression must not be silent again.
Also: the paste loop's NaN-landmark short-circuit never recorded its
frame in fallback_indices - in a device-output mode the tail's indexed
assignment length-mismatched (pinned red before the fix; the branch is
defensive today, the production interpolation fills NaN landmarks).
8 new bit-exactness pins (budget, selector, convert-out sub-chunking,
factor-4-scale, chunked assembly incl. group-boundary independence,
sentinels, end-to-end modes); the instrument gains the factor-4-scale
output-mode scenario. Verified on the CPU device only - no GPU run (the
CUDA before/after stays owner-gated). Gate: 461 passed, 6 skipped,
7 deselected, 0 failed.
The instrument now times the same paste_faces_batch call in the host and
the device output mode, one session, one fixture, and asserts the two
are bit-identical. On the CPU fixture (8 frames, 360x640, stub nets):
the output assembly's host<->device traffic is gone (1.06 MB each way
becomes 0, the ROI-sized staging recorded as roi_staged_bytes), wall
-8.8%, process CPU -8.7%. The delta dilutes the CUDA effect - on the
owner's GPU the kernel work stays on the GPU and the removed portion is
pure host time - so the CUDA measurement of the same comparison stays
the owner-gated V2.
The paste-stage attribution (tools/prof_paste_host_cpu.py, the CPU-device
stub run) showed the batch always takes the device path - the vendored
per-frame fallback never runs in the default configuration - and that the
remaining host cost of the step is the output assembly: the per-frame ROI
download, the whole-canvas host copy, the whole-stack np.stack and the
float math of the convert-out, all of which exist only because the output
stack is assembled in host memory.
F1 keeps the stack on the device: batched_bg_frames(return_device=True),
paste_faces_batch(device_output=True) scatters the blended ROI patches
into one uint8 device canvas, and the paste step assembles the batch with
one indexed copy, one stacked upload of the vendored-fallback frames and
a single bgr_u8_batch_to_comfy on the device. Nothing is downloaded or
copied per frame. The mode is off on a CPU device, over the 1 GiB
PASTE_DEVICE_STACK_MAX_BYTES budget and when nothing is eligible, so the
host path - and every existing pin - runs byte-for-byte as before; the
bytes that would have travelled are kept as roi_staged_bytes.
The new pin test_the_device_output_stack_is_bit_identical_to_the_host_stack
pins the canvas against the host stack on a CPU device. Gate: 451 passed,
6 skipped, 7 deselected.