hybrid: a modeset, from a process

H3 of docs/plan/hybrid.md -- "a modeset API, which is the thing an
out-of-kernel GPU driver makes affordable and an in-kernel one never got".

    # schmode modes
    1280x800  *
    1280x720
    1024x768
    800x600
    640x480
    # schmode 1024 768
    1024x768 ok

Captured off the virtio-gpu head, the frames really come back 1280x800,
1024x768, 640x480 and 1280x800 again, with the checkerboard band showing no
shear at any of them.

Nothing in the kernel changed for this. No syscall on the path has heard of
a scanout: schmode writes a line to a socket and vgpud sends five commands
to the device. The comparison is the point -- the same five commands in the
kernel would have been the same five commands *and a reason to be nervous*,
because a wrong one there takes the machine instead of one process. That is
why the in-kernel driver never grew one: not difficulty, exposure.

The framebuffer is allocated once, at the largest mode, and every smaller
mode reuses it. PCIIOC_DMA has no free -- a driver's blocks come back when
it exits and not before -- so a modeset that allocated would spend sixteen
slots and then the arena, and the failure would look like a GPU bug rather
than like counting. A larger mode is refused and says why.

vgpud used to end in for(;;) sleep(100) under a comment arguing that
building a control socket before there is a compositor to judge it is the
mistake this plan warns about. That was right about a *compositor protocol*
and wrong as a reason to have no socket: a modeset has a consumer that
exists, somebody changing the mode and looking at the screen, and schmode
is small enough to judge an interface this small. What is deliberately not
on that socket is everything a compositor would need -- no buffer
submission, no damage, no vblank -- which still waits, for the original
reason.

H4, the USB eviction, is now the only milestone left on the plan and is by
some distance the largest thing on the register.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
This commit is contained in:
Nexoniarz 2026-09-14 01:36:05 +02:00
commit ef3e191c6f
7 changed files with 467 additions and 21 deletions

View file

@ -158,7 +158,7 @@ is that the storm detector built for history/kernel.md section 13 named the
line, the rate and the neighbour without anyone having to look.
**All four mechanisms now exist.** What remains on this plan is the second
eviction and then the foreign driver host.
eviction -- USB -- and then the foreign driver host.
### One thing the interface is deliberately not
@ -245,6 +245,73 @@ way rather than counted here.
---
## A modeset, from a process
H3 is one sentence in the milestone table -- *"a modeset API, which is the
thing an out-of-kernel GPU driver makes affordable and an in-kernel one never
got"* -- and the claim in it is worth testing rather than repeating.
```
# schmode
1280x800 current
1280x800 maximum, framebuffer 4000 KB
# schmode modes
1280x800 *
1280x720
1024x768
800x600
640x480
# schmode 1024 768
1024x768 ok
```
The scanout really resizes: captured from the virtio-gpu head, the frames come
back 1280x800, then 1024x768, then 640x480, then 1280x800 again, with the
checkerboard band showing no shear at any of them.
**Nothing in the kernel changed for this.** No syscall on the path has heard of
a scanout; `schmode` writes a line to a socket and `vgpud` sends five commands
to the device. That is the whole of the milestone, and the reason it is
interesting is the comparison: the same five commands in the kernel would have
been the same five commands *and a reason to be nervous*, because getting the
sequence wrong there takes the machine instead of one process. **That is why
the in-kernel driver never grew one** -- not difficulty, exposure.
### What it costs, and what it refuses
The framebuffer is allocated **once, at the largest mode**, and every smaller
mode reuses it. `PCIIOC_DMA` has no free -- a driver's blocks come back when it
exits and not before -- so a modeset that allocated would spend sixteen slots
and then the arena, and the failure would look like a GPU bug rather than like
counting. A mode larger than the initial allocation is refused, and says why:
```
# schmode 1920 1080
refused: larger than the framebuffer, which is fixed at startup
```
That bound is 4 MB, `PCIIOC_DMA`'s cap, which at 32 bits per pixel is about
1280x800. Raising it is a one-line change to a constant and a question about
how much of a 16 MB arena one driver should be able to take, which is a better
question than it looks and is not answered here.
### The socket, and the argument it settles
`vgpud` used to end in `for(;;) sleep(100);` under a comment arguing that
building a control socket before there is a compositor to judge it is exactly
the mistake this document spends a section warning about.
That argument was right about a *compositor protocol* and wrong as a reason to
have no socket at all. A modeset API has a consumer that exists -- somebody
changing the mode and looking at the screen -- and `schmode` is small enough
that it can judge an interface this small. So the socket is there, it speaks
lines of text for the same reasons
[../architecture/debugging.md](../architecture/debugging.md) gives, and what is
deliberately **not** on it is everything a compositor would need: no buffer
submission, no damage, no vblank. Those still wait, for the original reason.
---
## The mechanisms
Four, and only the fourth is large.
@ -357,8 +424,8 @@ start because the display driver is a process that needs a compositor.
| **H0** | Mechanisms 2, 3 and 4, each with a test that exercises it from a userspace program against a device nothing else is using. | done |
| **H1** | A userspace virtio-gpu driver, publishing `display_ops` across the channel. Schcom talks to it and does not know the difference. | done, except that Schcom does not talk to it -- `cmd/vgpud` holds the device and draws its own frame |
| **H2** | Kill the driver process on purpose. The screen falls back to VBE, the driver restarts, the compositor reattaches. **This is the milestone that proves the whole idea**, and it is the one that cannot be skipped. | done, less the compositor -- see "The driver came back" |
| **H3** | A modeset API, which is the thing an out-of-kernel GPU driver makes affordable and an in-kernel one never got. | |
| **H4** | USB, same shape. | |
| **H3** | A modeset API, which is the thing an out-of-kernel GPU driver makes affordable and an in-kernel one never got. | done -- see "A modeset, from a process" |
| **H4** | USB, same shape. | the one left, and much the largest |
---