# Terminal Engine & GPU UI Rendering

> The terminal model and shell-session layer in warp_terminal, and the warpui windowing/rendering stack (wgpu, glyph cache, font atlas) that paints blocks, the editor, and panels.

- Repository: warpdotdev/warp
- GitHub: https://github.com/warpdotdev/warp
- Human wiki: https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5
- Complete Markdown: https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/llms-full.txt

## Source Files

- `crates/warp_terminal/src/lib.rs`
- `crates/warp_terminal/src/shared_session.rs`
- `crates/warpui/src/lib.rs`
- `crates/warpui/src/rendering/mod.rs`
- `crates/warpui/src/rendering/glyph_cache.rs`
- `crates/editor/src/lib.rs`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [crates/warp_terminal/src/lib.rs](crates/warp_terminal/src/lib.rs)
- [crates/warp_terminal/src/model/mod.rs](crates/warp_terminal/src/model/mod.rs)
- [crates/warp_terminal/src/model/grid/flat_storage/mod.rs](crates/warp_terminal/src/model/grid/flat_storage/mod.rs)
- [crates/warp_terminal/src/model/grid/cell_type.rs](crates/warp_terminal/src/model/grid/cell_type.rs)
- [crates/warp_terminal/src/model/block_id.rs](crates/warp_terminal/src/model/block_id.rs)
- [crates/warp_terminal/src/shared_session.rs](crates/warp_terminal/src/shared_session.rs)
- [crates/warp_terminal/src/shell/mod.rs](crates/warp_terminal/src/shell/mod.rs)
- [crates/warpui/src/lib.rs](crates/warpui/src/lib.rs)
- [crates/warpui/src/rendering/mod.rs](crates/warpui/src/rendering/mod.rs)
- [crates/warpui/src/rendering/glyph_cache.rs](crates/warpui/src/rendering/glyph_cache.rs)
- [crates/warpui/src/rendering/atlas/mod.rs](crates/warpui/src/rendering/atlas/mod.rs)
- [crates/warpui/src/rendering/atlas/manager.rs](crates/warpui/src/rendering/atlas/manager.rs)
- [crates/warpui/src/rendering/wgpu/mod.rs](crates/warpui/src/rendering/wgpu/mod.rs)
- [crates/warpui/src/rendering/wgpu/renderer.rs](crates/warpui/src/rendering/wgpu/renderer.rs)
- [crates/warpui/src/rendering/wgpu/renderer/frame.rs](crates/warpui/src/rendering/wgpu/renderer/frame.rs)
- [crates/warpui/src/rendering/wgpu/renderer/glyph.rs](crates/warpui/src/rendering/wgpu/renderer/glyph.rs)
- [crates/warpui/src/windowing/mod.rs](crates/warpui/src/windowing/mod.rs)
- [crates/warpui_core/src/scene.rs](crates/warpui_core/src/scene.rs)
- [crates/warpui_core/src/rendering/mod.rs](crates/warpui_core/src/rendering/mod.rs)
- [crates/editor/src/lib.rs](crates/editor/src/lib.rs)
- [crates/editor/src/render/mod.rs](crates/editor/src/render/mod.rs)
- [crates/editor/src/editor.rs](crates/editor/src/editor.rs)
</details>

# Terminal Engine & GPU UI Rendering

Warp's client is built from two cooperating layers. `warp_terminal` owns the *terminal model*: the ANSI/escape-sequence parser, the cell grid, the scrollback buffer, and the shell-session metadata that turns raw PTY bytes into structured, block-addressable content. `warpui` (with its platform-agnostic core `warpui_core`) owns the *rendering and windowing stack*: a retained `Scene` graph of rectangles, images, and glyphs that a GPU backend (wgpu, or native Metal on macOS) paints into the window, backed by a glyph cache and a texture atlas. The `editor` crate sits between them, rendering marked-up rich text (blocks, the command editor, panels) into the same `Scene` primitives.

This page traces how those pieces fit together: how terminal state is stored, how the UI describes what to draw, and how text becomes pixels through the glyph cache, font atlas, and wgpu render pipelines.

## Layer Architecture and Ownership

`warp_terminal` is intentionally thin at the root — `lib.rs` exposes only the `model`, `shell`, and `shared_session` modules ([crates/warp_terminal/src/lib.rs:1-3]()). The real weight lives in `model`, which re-exports the grid, ANSI handling, block indexing, and keyboard-mode types ([crates/warp_terminal/src/model/mod.rs:1-14]()).

`warpui` is a platform-facing wrapper that re-exports everything from `warpui_core` and adds `fonts`, `platform`, `rendering`, and `windowing` modules ([crates/warpui/src/lib.rs:1-7]()). The retained-scene types (`Scene`, `Layer`, `Glyph`, `GlyphKey`) live in `warpui_core` ([crates/warpui_core/src/scene.rs:17-97]()), while GPU device handling and the glyph cache live in `warpui` so they can be compiled per platform.

```mermaid
flowchart TB
    subgraph terminal["warp_terminal (terminal model)"]
        grid["model::grid::FlatStorage\nscrollback + cells"]
        ansi["model::ansi / escape_sequences"]
        block["model::BlockId\nblock identity"]
        shell["shell::Shell\nshell metadata"]
    end
    subgraph editor["editor (rich-text layer)"]
        rtv["EditorView / RichTextElement\nrender::element + layout"]
    end
    subgraph core["warpui_core (retained scene)"]
        scene["Scene / Layer\nrects, images, glyphs, icons"]
        cfg["rendering::Config\nGlyphConfig, GPUPowerPreference"]
    end
    subgraph ui["warpui (GPU + windowing)"]
        wgpu["rendering::wgpu::Renderer\nrect/glyph/image pipelines"]
        cache["GlyphCache + atlas::Manager\n1024² texture atlases"]
        win["windowing (winit) / platform (mac Metal)"]
    end
    ansi --> grid --> block
    grid --> rtv
    shell --> rtv
    rtv --> scene
    cfg --> scene
    scene --> wgpu
    wgpu --> cache
    wgpu --> win
```

Sources: [crates/warp_terminal/src/lib.rs:1-3](), [crates/warp_terminal/src/model/mod.rs:1-14](), [crates/warpui/src/lib.rs:1-7](), [crates/warpui/src/rendering/mod.rs:1-8](), [crates/warpui_core/src/scene.rs:17-38](), [crates/editor/src/render/mod.rs:1-13]()

## The Terminal Model

### Scrollback storage: `FlatStorage`

The terminal grid is stored in `FlatStorage`, a space-efficient flat buffer purpose-built for scrollback. Its module docs explain the trade-off: it is optimized for `Index`, `Scan`/`Iterate`, `Push`, and `Pop`, but deliberately *not* for `Insert`, because inserting into the middle of a flat array requires shifting all trailing data — acceptable for immutable scrollback rows but avoided on the active region ([crates/warp_terminal/src/model/grid/flat_storage/mod.rs:1-17]()).

Rather than storing styling per cell, `FlatStorage` keeps the text content compact and pushes color and style into interval maps. The struct holds the `Content` buffer, an `Index` mapping row numbers to content offsets, the column width, an `fg_color_map`, a `bg_and_style_map`, an optional `end_of_prompt_marker`, and a `max_rows` cap with a `num_truncated_rows` counter for bounded scrollback ([crates/warp_terminal/src/model/grid/flat_storage/mod.rs:45-72]()).

```text
FlatStorage
 ├─ content: Content            (flat char buffer)
 ├─ index: Index                (row → byte offset)
 ├─ columns: usize
 ├─ fg_color_map  ─┐ interval maps keyed by content offset
 ├─ bg_and_style_map ┘ (color/style stored as ranges, not per-cell)
 ├─ end_of_prompt_marker: Option<..>
 └─ max_rows / num_truncated_rows  (bounded scrollback)
```

Sources: [crates/warp_terminal/src/model/grid/flat_storage/mod.rs:1-90]()

### Cells, wide characters, and blocks

Each grid cell is classified by `CellType`, which distinguishes a `RegularChar` from the components of a double-width glyph: `WideChar`, `WideCharSpacer`, and `LeadingWideCharSpacer` (used when a wide char must wrap to the next row). The conversion from `&Cell` is tuned so the common narrow-character case resolves with a single flag comparison before checking the rarer wide-cell flags ([crates/warp_terminal/src/model/grid/cell_type.rs:2-37]()).

Output is grouped into *blocks* identified by `BlockId`. A block produced from PTY output takes the form `{WARP_SESSION_ID}-{NUM_ID}` with a monotonically increasing per-session counter, because that ID originates in the shell `precmd` hook where generating a UUID would be too expensive; blocks created inside the app use a UUID instead ([crates/warp_terminal/src/model/block_id.rs:4-11]()).

Sources: [crates/warp_terminal/src/model/grid/cell_type.rs:2-37](), [crates/warp_terminal/src/model/block_id.rs:1-11]()

### Shell session layer

The `shell` module models the shell and its configuration. `Shell` carries the `shell_type`, optional `version`, shell `options`, autodetected `plugins` (e.g. Powerlevel10k, flagged for special handling), and the absolute path to the running shell binary ([crates/warp_terminal/src/shell/mod.rs:78-91]()). It also handles platform path quirks — Windows `PATHEXT` extension elision and zsh extended-history prefix stripping done with hand-rolled string parsing to stay fast on a hot path ([crates/warp_terminal/src/shell/mod.rs:29-76]()).

`shared_session.rs` is the bridge to session sharing: it provides `From` conversions between the model's `Point` (row/col) and the `session_sharing_protocol::common::Point`, so terminal coordinates can cross the session-sharing boundary without coupling the model to the protocol ([crates/warp_terminal/src/shared_session.rs:1-19]()).

Sources: [crates/warp_terminal/src/shell/mod.rs:29-91](), [crates/warp_terminal/src/shared_session.rs:1-19]()

## The Retained Scene Graph

The UI does not issue draw calls directly; it builds a `Scene`. A `Scene` holds a `scale_factor`, a `rendering::Config`, and a stack of `Layer`s plus overlay layers ([crates/warpui_core/src/scene.rs:17-27]()). Each `Layer` is a flat bucket of primitives — `rects`, `images`, `glyphs`, `icons` — plus optional `clip_bounds` and an R-tree `hit_map` for hit testing ([crates/warpui_core/src/scene.rs:29-38](), [crates/warpui_core/src/scene.rs:56-68]()).

A `Glyph` references a `GlyphKey` (glyph id, font id, and font size), a screen `position`, an optional `fade`, and a `color` ([crates/warpui_core/src/scene.rs:70-97]()). The `GlyphKey` is the cache key that ties the scene to the rasterizer. Application-wide rendering knobs live in `rendering::Config`: a `GlyphConfig` (thin-stroke policy via `ThinStrokes`), a `GPUPowerPreference`, and an optional `backend_preference` ([crates/warpui_core/src/rendering/mod.rs:45-75]()).

Sources: [crates/warpui_core/src/scene.rs:17-97](), [crates/warpui_core/src/rendering/mod.rs:45-75]()

## The Rich-Text Editor Layer

The `editor` crate renders Warp's marked-up content — command blocks, the multiline input editor, list/table/code elements, and panels. Its root declares the rendering machinery (`content`, `decoration`, `render`, `multiline`, `search`, `selection`) ([crates/editor/src/lib.rs:1-9]()), and `render/mod.rs` describes itself as the "Rich Text Editor rendering layer — model and UI element for rendering marked-up rich text," defining layout constants such as icon-button size and block-footer height ([crates/editor/src/render/mod.rs:1-13]()).

The `EditorView` trait is the contract between a `RichTextElement` and its containing view: it resolves runnable-command and embedded-item models by block offset and supplies `text_decorations` (syntax highlighting, underlines) for viewport ranges, with lifetimes carefully tied to cached `RangeMap` data accessed through `AppContext` ([crates/editor/src/editor.rs:18-56]()). The editor's output is ultimately the same `Scene` glyphs and rects consumed by the GPU renderer below.

Sources: [crates/editor/src/lib.rs:1-9](), [crates/editor/src/render/mod.rs:1-13](), [crates/editor/src/editor.rs:18-56]()

## GPU Rendering: wgpu Backend

### Instance and adapter management

The wgpu module owns a single global `wgpu::Instance` behind a `LazyLock<Mutex<Option<Arc<..>>>>`, initialized once via `init_wgpu_instance` and replaceable via `reset_wgpu_instance` ([crates/warpui/src/rendering/wgpu/mod.rs:16-30]()). Initialization runs on a dedicated thread (except on wasm) but blocks the caller until the lock is acquired, so `get_wgpu_instance()` can never race with setup ([crates/warpui/src/rendering/wgpu/mod.rs:112-142]()). The module also handles platform-specific concerns: Windows DirectComposition toggling and DX12 shader-compiler selection, and on Linux it suppresses `WAYLAND_DISPLAY` when the app forces X11 to avoid an instance/window-handle mismatch crash ([crates/warpui/src/rendering/wgpu/mod.rs:33-110]()).

Dual-GPU machines are detected through `is_low_power_gpu_available`, which checks whether any adapter is an `IntegratedGpu`; the result is memoized in a `OnceLock` because the probe is expensive ([crates/warpui/src/rendering/mod.rs:10-29](), [crates/warpui/src/rendering/wgpu/mod.rs:191-198]()).

Sources: [crates/warpui/src/rendering/wgpu/mod.rs:16-198](), [crates/warpui/src/rendering/mod.rs:10-29]()

### Renderer, pipelines, and frame drawing

`Renderer` holds three render pipelines — `rect`, `glyph`, and `image` — all configured with alpha blending against the surface format ([crates/warpui/src/rendering/wgpu/renderer.rs:24-62]()). Its `render` method builds a `Frame`, acquires the surface texture, encodes draw calls, submits them, optionally captures or runs a pre-present callback, and presents only if no GPU error occurred (a separate `Error::DeviceLost` is surfaced by unwrapping nested wgpu errors) ([crates/warpui/src/rendering/wgpu/renderer.rs:64-173]()).

`Frame::new` walks every `Layer` and lets each pipeline collect per-layer state, then finalizes per-frame GPU buffers ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:27-79]()). `Frame::draw` opens a single render pass that clears to transparent, then for each layer sets a scissor rect from the layer's `clip_bounds` (skipping layers that don't intersect the window) and draws **rects, then images, then glyphs** in that order ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:84-158]()). On drop, the frame tells the image pipeline to clean up its cache ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:179-185]()).

```mermaid
sequenceDiagram
    participant R as Renderer.render
    participant F as Frame
    participant GP as glyph::Pipeline
    participant GC as GlyphCache
    participant Atlas as atlas::Manager
    participant GPU as wgpu Device/Queue

    R->>F: Frame::new(scene, pipelines)
    loop each Layer
        F->>GP: initialize_for_layer(layer)
        loop each Glyph
            GP->>GC: get(glyph_key, scale, subpixel)
            alt cache miss
                GC->>GC: raster_bounds_fn + rasterize_glyph_fn
                GC->>Atlas: insert(size) -> TextureId + region
                GC->>GPU: insert_glyph_into_texture(queue)
            end
            GC-->>GP: GlyphTextureOffset (uv + bounds)
        end
        GP->>GP: group GlyphInstanceData by TextureId
    end
    R->>F: draw(encoder, surface_texture)
    F->>GPU: render pass -> rects, images, glyphs
    R->>GPU: queue.submit + surface.present
```

Sources: [crates/warpui/src/rendering/wgpu/renderer.rs:24-173](), [crates/warpui/src/rendering/wgpu/renderer/frame.rs:27-185](), [crates/warpui/src/rendering/wgpu/renderer/glyph.rs:150-239]()

## Glyph Cache and Font Atlas

`GlyphCache<Texture>` caches rasterized glyphs into a series of `1024×1024` texture atlases (`ATLAS_SIZE = 1024`). It is generic over the texture type so the same logic serves different GPU backends, and it stores a `HashMap<GlyphCacheKey, GlyphTextureOffset>` alongside an `atlas::Manager` ([crates/warpui/src/rendering/glyph_cache.rs:13-42]()). The cache key combines the `GlyphKey`, the `scale_factor` (as `OrderedFloat`), and the `SubpixelAlignment`, so the same character rasterized at a different DPI or sub-pixel offset is a distinct entry ([crates/warpui/src/rendering/glyph_cache.rs:44-59]()).

`GlyphCache::get` is callback-driven, decoupling caching policy from GPU specifics. On a miss it computes raster bounds, skips zero-size glyphs, rasterizes (in `Rgba32`), allocates a region via the atlas manager, lazily creates a new texture when a fresh atlas index appears, uploads the pixels through `insert_into_texture`, and records a `GlyphTextureOffset` (texture id, allocated region, raster bounds, emoji flag) ([crates/warpui/src/rendering/glyph_cache.rs:93-149]()). If `GlyphConfig` changes, the whole cache is thrown away and rebuilt ([crates/warpui/src/rendering/glyph_cache.rs:80-86]()).

The `atlas::Manager` performs shelf-style allocation across multiple textures. Each `insert` returns a `TextureOffset`; when the current allocator reports `Full`, the manager bumps to the next `TextureId`, starts a fresh allocator, and retries — so glyphs overflow into additional atlas pages rather than failing ([crates/warpui/src/rendering/atlas/manager.rs:43-67]()). An `AllocatedRegion` carries both the UV (texture) rect and the pixel rect for a glyph ([crates/warpui/src/rendering/atlas/mod.rs:8-15]()).

The glyph pipeline consumes the cache during `initialize_for_layer`: for each scene glyph it computes a `SubpixelAlignment` from the scaled position, calls `glyph_cache.get` with closures that build a `TextureWithBindGroup` and upload pixels, then assembles a `GlyphInstanceData` (using the atlas region size, not the smaller render bounds, to avoid sampling artifacts) grouped per `TextureId` for batched draws ([crates/warpui/src/rendering/wgpu/renderer/glyph.rs:151-239]()).

| Concept | Type / value | Responsibility |
|---|---|---|
| Atlas page size | `ATLAS_SIZE = 1024` | Fixed square texture dimension ([glyph_cache.rs:13]()) |
| Cache key | `GlyphCacheKey` | `GlyphKey` + `scale_factor` + `SubpixelAlignment` ([glyph_cache.rs:44-49]()) |
| Cached value | `GlyphTextureOffset` | texture id, region, raster bounds, `is_emoji` ([glyph_cache.rs:62-68]()) |
| Overflow strategy | `atlas::Manager::insert` | New `TextureId` + allocator when full ([manager.rs:54-67]()) |
| Config invalidation | `update_config` | Rebuild cache when `GlyphConfig` changes ([glyph_cache.rs:80-86]()) |

Sources: [crates/warpui/src/rendering/glyph_cache.rs:13-149](), [crates/warpui/src/rendering/atlas/manager.rs:43-67](), [crates/warpui/src/rendering/atlas/mod.rs:8-15](), [crates/warpui/src/rendering/wgpu/renderer/glyph.rs:151-239]()

## Windowing and Platform Backends

Rendering is split per platform. The `rendering` module gates the wgpu backend behind `#[cfg(wgpu)]` and selects atlas/glyph types through `pub(crate)` re-exports ([crates/warpui/src/rendering/mod.rs:1-8]()). macOS additionally has a native Metal renderer plus its own wgpu path under `platform/mac/rendering`, while Linux/FreeBSD use a winit-based `WindowingSystem` ([crates/warpui/src/windowing/mod.rs:1-6]()). The windowing layer also defines minimum window dimensions (`MIN_WINDOW_WIDTH`, `MIN_WINDOW_HEIGHT`), relaxed under test/integration builds ([crates/warpui/src/windowing/mod.rs:8-21]()).

Sources: [crates/warpui/src/rendering/mod.rs:1-8](), [crates/warpui/src/windowing/mod.rs:1-21]()

## Summary

Warp separates *what the terminal means* from *how it is painted*. `warp_terminal` turns PTY bytes into a compact, block-addressed model: `FlatStorage` keeps scrollback cheap by pushing color and style into interval maps, `CellType` tracks wide-character layout, and `BlockId` gives every command output a stable identity ([crates/warp_terminal/src/model/grid/flat_storage/mod.rs:45-72](), [crates/warp_terminal/src/model/block_id.rs:4-11]()). The `editor` crate renders that model — plus the input editor and panels — into a retained `Scene` of layers, rects, and glyphs ([crates/editor/src/render/mod.rs:1-13](), [crates/warpui_core/src/scene.rs:29-38]()). `warpui` then paints the scene through a wgpu `Renderer` whose glyph pipeline is fed by a `GlyphCache` over `1024²` texture atlases, batching per-texture instance data into a single render pass ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:84-158](), [crates/warpui/src/rendering/glyph_cache.rs:13-149]()).

This page synthesizes the repository implementation directly; the selected knowledge profile's solved-problem notes (`docs/solutions/`) and strategy anchor (`STRATEGY.md`) are not present in this checkout, so no such sources were used. Provider-neutral note: the rendering stack depends only on `wgpu`/native GPU APIs and the local font rasterizer, with no model-provider or hosted-service coupling, so any Grok-Wiki integration consuming this page stays portable across file, repository, or catalog skill sources.

Sources: [crates/warp_terminal/src/model/grid/flat_storage/mod.rs:45-72](), [crates/warpui/src/rendering/glyph_cache.rs:13-149](), [crates/warpui/src/rendering/wgpu/renderer/frame.rs:84-158]()
