← Crossware Engineering Hub / Articles

Traveo T2G · OTF & LBO, the whole story

The frame that never exists

On the Traveo T2G, an HMI built from OTF and LBO layers produces its final image as a live pixel stream assembled during scan-out — no composed frame is ever stored. This is the animated summary: what the modes are, how the line buffer races the beam, what the command buffers contain, when they execute, and how to debug it all.

The red line is the only place the final image ever exists.

01

Vocabulary: three modes, two destinations

LBO can write into a framebuffer ("LBO to memory") or straight to the display ("LBO to display") — and LBO-to-display is what everyone calls OTF. An OTF layer is an LBO layer whose destination is the display, not VRAM.

ModeHow it drawsFramebufferQML hint
IBOCommands execute directly into the framebufferFull, ×2NoRenderingHint
LBO → memoryCommands replayed line-by-line into the back bufferFull, ×2OptimizeForSpeed
OTFCommands replayed every refresh through a small line bufferNone — 128-line ringQUL default
02

The line buffer: racing the beam

Every refresh, the blit engine re-renders the OTF layer's content into a rolling ring of lines (128 on CYT4DN). Two pointers chase each other: the writer renders line N+k while the reader hands line N to the compositor. Watch them chase:

read by compositor rendered, waiting blit engine writing empty

The race. If a scanline costs too much to render, the writer stalls, the gap shrinks, and the reader catches up — tearing on exactly those rows. The 128-line depth is the safety margin; cheap regions bank a lead that expensive regions spend.

03

Final assembly: composition at scan-out

There is no buffer holding the final image. As the timing controller reaches each line, the composition engine streams that line's pixels from every layer source that overlaps it — OTF rings, LBO/IBO front framebuffers, even flash-backed image layers — blends them in fixed z-order with alpha and chroma key, and feeds the result directly to the panel. The scanlines below move in lockstep because they are the same instant:

Pixels, not line transactions. The blend is a hardware pipeline a few registers deep — a composed pixel exists for nanoseconds between the blend ALU and the panel pins. That's also why there's no free screenshot of the composed frame: it was never stored.

04

The compositor's own memory: tiny, and a second race

The compositor does need memory — per-layer fetch FIFOs that absorb bus-arbitration jitter, and an output FIFO crossing into the pixel-clock domain. Bytes to kilobytes of on-chip SRAM, fixed in silicon: latency hiding, not frame storage. That creates a second, separate race:

Race 1 — compute (blit engine vs scan-out, through the big 128-line ring): losing it tears specific rows; fixed on the rendering side. Race 2 — bandwidth (DMA vs pixel clock, through the tiny fetch FIFO): losing it corrupts the output stream itself; fixed by cutting the bandwidth bill — internal VRAM over contended HyperRAM, lower bpp, narrower layers. A bigger line buffer does nothing for race 2.

05

What the command buffers contain

An OTF command buffer is a program, not a picture: register-write entries that configure the blit engine, a kick to execute each object, and sync entries that pace replay against the beam. It carries addresses and parameters — never pixel arrays. "Geometry" on this 2.5D engine means a destination rectangle plus an optional affine transform; images, glyphs, and pre-rasterized shapes are all referenced by pointer into flash or VRAM. Watch the CmdSeq walk one frame:

Economics. Each object costs tens–hundreds of bytes of commands regardless of pixel area, so the 64 KB FIFO holds hundreds of objects — and exhausting it tracks element count, never element size. A property animation just patches a few bytes (a matrix, an alpha, a source pointer); an unchanged frame costs the CPU nothing at all.

06

When it executes: every refresh, paced by the beam

Execution is started by vsync, paced by line-sync entries, and spans the whole active frame — the CmdSeq stays between "just ahead" and 128 lines ahead of scan-out. Meanwhile the CPU records the next frame's program in the other buffer. One refresh period, on loop:

Safe decoupling. If the CPU misses a vsync, the CmdSeq simply replays program N again — a one-frame-stale but perfect image. UI rate can drop; display rate never does. Contrast LBO-to-memory: its commands run episodically, on content change, into the back framebuffer at memory speed with no beam chasing them, flipping at the next vsync.

Per OTF layer there are logically two command buffers — a front/back pair of programs, swapping at vsync exactly like framebuffers do, except what's double-buffered is the recipe rather than the pixels. That's what guarantees each refresh renders from one coherent frame description. With the platform maximum of two OTF layers, up to four command buffers are alive in the system; the per-layer FIFO size in setConfigForOTFLayer sizes this storage, and the linker map shows exactly how the port lays it out.

07

VRAM math and the debugging tree

The reason all this machinery exists, for a full-width layer on a 1280 × 480 cluster at 24 bpp:

LBO to memory  1280 × 480 × 3 B × 2  = ≈ 3.7 MB per layer
OTF            1280 × 128 × 3 B + 2 × 64 KB = ≈ 608 KB per layer

Sharp edge: never compress a transformed image asset — rotation reads source pixels out of decode order and blows the per-line budget. Pre-rendered sprite sequences are the architecturally correct answer for rotating needles.