Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ members = [
"lib/device-memory",
"lib/devicepath",
"lib/elf",
"lib/display-output",
"lib/edid",
"lib/elide",
"lib/fat32",
Expand Down
17 changes: 10 additions & 7 deletions images/system.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,13 @@ receives = ["power"]
# `screen`. `volume` is soundserver's master level and mute, which the volume
# keys set and no other row receives. The display is a virtio-gpu function the
# compositor drives, where the machine has one, and the firmware's framebuffer
# otherwise. `jobs` makes each program it starts a job of its own, with its own
# share of the CPU. `power` is its stop view's: Esc cancels the machine's stop,
# Enter forces it.
# otherwise; `display-output` is where a display driver offers the output it
# scans out and is told each frame composed into it. `jobs` makes each
# program it starts a job of its own, with its own share of the CPU. `power` is
# its stop view's: Esc cancels the machine's stop, Enter forces it.
[programs.compositor]
service = true
serves = ["compositor", "prompt", "clipboard", "input", "display"]
serves = ["compositor", "prompt", "clipboard", "input", "display", "display-output"]
receives = ["soundserver", "filepicker", "volume", "power"]
devices = ["pci:03:80:00/1af4:1050", "framebuffer"]
starts = ["terminal", "files", "/apps"]
Expand Down Expand Up @@ -134,11 +135,13 @@ syscap = ["rt"]

# The Tiger Lake display driver: the T14's iGPU, held for the boot. It keeps
# the firmware's mode and surface, which the compositor draws on through the
# kernel's framebuffer claim, and programs the display engine's power. Not
# started again: the claim's release resets the function, which ends the
# firmware's scan-out (`issues/each-gpu-drives-its-displays-from-a-userland-driver.md`).
# kernel's framebuffer claim, programs the display engine's power and answers
# the compositor's presents on `display-output`. Not started again: the
# claim's release resets the function, which ends the firmware's scan-out
# (`issues/each-gpu-drives-its-displays-from-a-userland-driver.md`).
[programs.tgl-display]
drives = ["pci:03:00:00/8086:9a49"]
receives = ["display-output"]

# The network stack, over every link a NIC driver brings on `link`; it claims
# no device. It serves from the start, links or none.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,13 @@ The kernel keeps only generic mechanisms:
- DC6 is allowed only with the panel on DDI A, since Vol 12 says only port A's PHY programming survives it.
- With the pipe lit, the engine enters DC5 only while PSR is active (Vol 12, "Display C5 and C6"), so this stage alone saves little.
- What it can show alone is the program held in storage, PG3-PG5 off, and the scan-out and `hda` unharmed. `hda`'s display codec is in PG3.
3. **Present and damage.** The `display-output` piece PSR needs is the compositor telling the driver which frame changed, and where. Otherwise PSR1 sees a CPU write only through FBC host tracking of a graphics-aperture fence (Vol 12 "CPU Host Front Buffer Tracking", "on projects that support that"). Whether that reaches the GOP's surface is unverified. This is ordered before PSR, rather than an interim signal. Its shape goes to the orchestrator before it is built, because it crosses the compositor.
3. **Present and damage.** The `display-output` piece PSR needs is the compositor telling the driver which frame changed, and where. Without it, PSR1 sees a CPU write only through FBC host tracking of a graphics-aperture fence (Vol 12 "CPU Host Front Buffer Tracking", "on projects that support that"). It is ordered before PSR, rather than an interim signal. Shape approved by the orchestrator, 2026-11-01.
- `lib/display-output` owns the wire types and the compositor's state: `Hello{size}`, `Present{sequence, damage}` and `Presented{sequence, vblank_nanos, refresh_interval_nanos}`.
- One present is outstanding at a time. Damage composed meanwhile is merged, past 8 rectangles into their bounding box, and sent when the answer arrives.
- The compositor serves `display-output`, one driver at a time, and never waits on it.
- `tgl-display` answers each present at the vblank after it arrived. That vblank is pipe A's interrupt, enabled only while a present waits, and its wait has a hang ceiling.
- When a connection a present arrived on ends from the compositor's side (a restart, a `swap`, or the compositor dropping the driver), the driver connects again, at most 8 times a boot. A protocol refusal, or a connection that ended before any present arrived on it, ends presents for the boot, by name.
- The compositor does not yet pace frames by `Presented`. It still blits the firmware's framebuffer itself until stage 5.
4. **PSR on the eDP panel**, measured together with stage 2. PSR's first-frame exit latency goes to the owner in absolute numbers before PSR lands.
5. **The rest of `display-output`.** virtio-gpu and the framebuffer become drivers. The panic surface lands here.
6. **Intel modesetting**: combo-PHY DDIs, DPLLs and CDCLK, DP link training with DSC, HDMI 2.0 with SCDC, EDID over AUX and GMBUS, several outputs.
Expand Down
14 changes: 14 additions & 0 deletions lib/display-output/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "toyos-display-output"
description = "The compositor's display-output protocol: the output a display driver offers, the frames the compositor presents to it and their answers, decoded once."
version = "0.1.0"
edition = "2024"
license = "MIT OR Apache-2.0"
publish = false

[lib]
doctest = false

[lints.rust]
unsafe_code = "forbid"
warnings = "deny"
Loading