Repository navigation
Conversation
The design round's empty commit. The design and its roast are the pull request's body; the build drops this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
|
The orchestrator, on the design's two decisions:
|
|
Design review, round 1: head Read against:
The orchestrator's rulings are taken as given: S1 first, the lending limit raised in S1, and Weighed
Where this review rests on Linux. In one place: I read GNOME Mutter's
The design rests on Linux in three places: B10 (Mutter), N8 (M1 through Ubuntu's sysfs) and N9 (KMS). BLOCKER
NOTE
DESIGN NEEDS CHANGES: fence every completion the design relies on (§5.7.6.5); keep one virtio-gpu guest smoke; make the cursor queue read-only, with QEMU's |
Design round. Nothing is built. The owner's go: a display scale factor (pixel density) and live resize / resolution change, on QEMU and on metal alike. Each stage below is its own pull request, built only once this design is accepted in a comment here. The branch carries only the empty design commit, which the build drops. Production and test lines: 0.
What this was read from:
mainatab655a115.c3d48b7), edk205b96e3, virtio 1.2 cs01, wayland93c04ad3, wayland-protocols35d9638c, Mutter65fc6baa, and the winit fork'stoyos-0.30.13atf58e1f3b(the commitCargo.lockconsumes). Every file and line is in sources.txt.What was measured:
What the tree has
kernel/src/drivers/virtio_gpu.rsandkernel/src/drivers/gop.rs. They sit behind theGputrait (kernel/src/gpu.rs) and four syscalls:SYS_GPU_PRESENT,_SET_CURSOR,_MOVE_CURSORand_SET_RESOLUTION. The compositor holds theframebufferclaim and calls them (sdk/toyos/src/gpu.rs). Moving virtio-gpu out is stage 1 ofissues/every-driver-is-still-in-the-kernel.md.screen WxH(toybox) sendsMSG_SET_RESOLUTION, which callsSYS_GPU_SET_RESOLUTION. The kernel makes a new resource and scanout, and the compositor reflows its windows (system/compositor/src/session.rs:1155).NotSupported(gop.rs:21), and the compositor drops that without a word.VIRTIO_GPU_EVENT_DISPLAY. The kernel driver spin-polls its used ring (drivers/virtio.rs:534) and takes no config interrupt.virtio_gpu.rs:592-606).GET_DISPLAY_INFOis never sent.Chrome::DEFAULT, in pixels (system/compositor/desktop/src/layout.rs:83).build/assets.rs:301).build/icons.rs:27).sdk/window/src/lib.rs:243,279,292).scale_factor()with 1.0, and takes a requested size as physical at 1.0 (src/platform_impl/toyos/window.rs:31-34,86-89).sdk/toyos/src/surface.rscarries key transitions down the surface tree and no pixels. Nothing in it changes.toyos-window'sWindow(sdk/window), with winit's ToyOS backend over it.Window. calc, snake and doom draw through winit and softbuffer.kernel/src/pcidev/mod.rs:152,156).MAX_FUNCTIONSis 4 (:146). The Virtio profile's three claims (net, sound, NVMe) plus the GPU take all four.What QEMU does
Read from the QEMU 11.1.1 source:
cocoa reports the window in backing pixels and in millimetres. On a window resize,
updateUIInfoLockedsends two things throughqemu_console_set_ui_info, debounced by 1 s:backingScaleFactor;width_mm/height_mm: the frame's share ofCGDisplayScreenSize.So on a Retina panel the guest is offered the window's real pixels and the panel's real density.
virtio-gpu turns that into the spec's event.
virtio_gpu_ui_infostores the report as the scanout's preferred size and mm. It setsVIRTIO_GPU_EVENT_DISPLAYinevents_readand sends a config notification.GET_DISPLAY_INFOanswers that size.GET_EDIDgenerates an EDID from it, at 100 dpi when no mm is known.xresxyres.The trigger. cocoa's
zoom-to-fitdefaults to off.zoom-to-fitto on for virtio-gpu (qapi/ui.json).GTK reports logical pixels and no mm. On a HiDPI Linux host the guest is offered a smaller mode at 100 dpi, and GTK scales it up. That is QEMU's to fix, not ToyOS's.
OVMF publishes no EDID protocol on its
-vga stdGOP (QemuVideoDxe/Initialize.c:380is a TODO). The GOP profiles and metal-sim boot with no panel size.Measured with QEMU 11.1.1's
qemu-edid, which calls the same generator the device answersGET_EDIDwith:0xF7. The mode is in a DisplayID extension in the third block, which carries no size.A full-screen window on a fast panel crosses QEMU's large-screen line: 4096 pixels, or a 655.36 MHz pixel clock. So the parser must tell a descriptor from a timing. When there is no timing, the size comes from the base block.
Not measured:
system_profiler).Order
S2 could come first only if the kernel driver copies its boot-time
GET_EDIDinto the claim. That is about 20 lines, which S1 then deletes. I recommend S1 first.Who owns what
pci:1af4:1050claim; the driver is the cratesystem/compositor/virtio-gpuontoyos-virtio(S1)framebufferclaim. The claim carries the EDID block the loader read, unparsed (S2)lib/edid, a crate of its own because it decodes a device's bytes (S2)toyos-desktop(S1, S2)toyos-window'sWindowInfoandResizeInfo(S2)scale_factorandScaleFactorChanged(S2)toyos-font, from the TTF (S2)sprite(S2)screen scale; the compositor answers it and keeps it (S2)M1. Each laptop's panel size, and whether its firmware publishes it
EFI_EDID_ACTIVE_PROTOCOLandEFI_EDID_DISCOVERED_PROTOCOLon the GOP's handle and prints:SizeOfEdid;lib/edidfixtures. The T14's is read under its Ubuntu (/sys/class/drm/card*-eDP-*/edid); the AMD bench's is read the same way where it boots Linux. Before committing:0xFFserial descriptor are zeroed;_DDCon the panel's device, which acpiserver can evaluate.S1. virtio-gpu leaves the kernel; the compositor drives it and follows the host's window
Issue: stage 1 of
issues/every-driver-is-still-in-the-kernel.md, its virtio-gpu half. S1 also meets the exits ofthe-gpu-driver-asserts-on-what-the-device-answers.mdandthe-second-scanout-buffer-is-read-by-nobody.md.Design.
The holder is the compositor.
system.tomlgainspci:1af4:1050besideframebuffer.The driver is
system/compositor/virtio-gpu, besidesystem/soundserver/virtio-sound.toyos-virtio'sRegistersandDmaBuffers, and host-tested on its stub.One MSI-X entry serves both the control queue and configuration changes (
Setup::config_vector, as netstack does). The claim's record joins the compositor's poller beside the keyboard and mouse.The output is read the same way at start and on every event (virtio 1.2 §5.7.4.2, §5.7.5):
events_clearwith whatevents_readholds.GET_DISPLAY_INFOandGET_EDID(0).Clearing first means an event that lands during the reads raises another notification and is not lost.
A mode change is a page flip (§5.7.6.3). The old mode stays on screen until
SET_SCANOUT:RESOURCE_CREATE_2D(the next id) andRESOURCE_ATTACH_BACKING.TRANSFER_TO_HOST_2D(whole),SET_SCANOUT,RESOURCE_FLUSH(whole).RESOURCE_UNREFthe old resource, then unlend its backing and drop it. The IOMMU mapping goes even if the device refuses the unref, so the device never reaches those pages again.A refusal before step 3 unrefs the new resource, drops its backing, keeps the old mode, and is logged by name. There is one backing per mode, so the second scanout goes.
A present is
TRANSFER_TO_HOST_2DandRESOURCE_FLUSHper damaged rectangle.The cursor is the cursor queue's
UPDATE_CURSORandMOVE_CURSOR, sent by the compositor.MSG_SET_RESOLUTIONtakes the same flip at the asked size on virtio.What the kernel loses:
drivers/virtio_gpu.rsand theGputrait;SYS_GPU_*numbers andtoyos::gpu;GOP stays as the claim's one scanout. The compositor presents it with its own write-combining blit and
sfence;SYS_GPU_PRESENTwas already a no-op for it.pcidev's bounds.
The issue's control obligation lands in this diff, as the issue states. The IOMMU decline is made in
toyos-virtio'sOffer::acceptfor a function a process drives, and it reds when that function keepsFEATURES_OK.Profile::HeadlessVirtioGpugoes.The development host. On macOS,
build/qemu.rspasses-display cocoa,zoom-to-fit=on, which is what QEMU already gives GTK for this device by default.xres=1280,yres=720stays, as the size before the window reports.Roast.
This is the tracked stage, and it is bigger than the feature asked for. The alternative keeps the driver in the kernel:
That is new kernel code and new
SYS_GPU_*ABI for work that netstack and soundserver show userland owns. It also goes against the issue's ruling that no syscall carries a GPU operation. Rejected.A GPU driver bug now ends the compositor, not the kernel. The desktop cannot outlive its display, and the kernel no longer dies on a device's answer.
The compositor blocks on its own device during a flip and during each frame's transfers, bounded and failing loudly. The server doctrine forbids blocking on a client, not on the server's own device.
The lend window grows for every claim, not only the display's. It is address space. The grant bound, which is what protects memory, is unchanged.
The Virtio profile then uses four of four PCI function slots. The next PCI claim on it needs
MAX_FUNCTIONSraised.The panic console still shows nothing on the Virtio profile. OVMF's virtio-gpu GOP is Blt-only and publishes no framebuffer, as today.
screen WxHand the host window can disagree, and the later one wins. Withzoom-to-fit, a mode the user set lasts until the window is next resized.Checks.
toyos-virtio's stub:SET_SCANOUTandRESOURCE_UNREF;SET_SCANOUT, and accepting an error answer.cargo runon the Mac, drag the window, and go full screen. The compositor logs one line per event naming the mode, the mm and the scale, and the picture is sharp.S2. The scale
Issue: stage 5 of
issues/toyos-has-a-desktop.md.Design.
The model is fractional-scale-v1's, physical-first.
n/120, fractional-scale-v1's representation.wp_viewport, and so does a Windows app that is per-monitor DPI aware (v2).na multiple of 120.macOS's model was considered and rejected. There, apps render at an integer backing scale (1 or 2), and the window server resamples the whole screen to a non-integer "looks like" mode.
No compositor upscaling of a client that ignores the scale, the way Wayland upscales a
buffer_scale1 surface. Every ToyOS client renders at scale. A third-party app that ignoresscale_factordraws small, as it would on Windows.The compositor decides the scale, purely, in
toyos-desktop:calculate_scale). Mutter's comment says its 135 dpi target matches the defaults of macOS, Android, iOS and Windows.screen scale 1.25orscreen scale autosendsMSG_SET_SCALE.HOME(/state/compositor): one writer and one reader.-display none: 1;EDID is decoded by
lib/edid, which isno_stdand has nounsafe:Nothing else is read: the mode comes from the device or the firmware.
GOP's EDID travels unparsed:
EFI_EDID_ACTIVE_PROTOCOL's base block beforeExitBootServices.FramebufferInfo, as 128 bytes and a length.Rounding is fractional-scale-v1's: half away from zero, in integers.
px(l) = sign(l)·((|l|·n + 60) / 120). A rectangle scales by its corners, not by its origin and size, so two rectangles that touch still touch at any scale.The wire (
toyos-window):WindowInfoandResizeInfogainscale. A window whose size or scale changed gets a new buffer andMSG_WINDOW_RESIZED, as a size change does today.CreateWindowRequest's size is logical, as winit's Wayland backend takes a new window's size. The compositor converts it.CursorMovedis.ResolutionInfogainsscale, soscreenprints1920x1080 @ 1.25.Windowgainsscale_factor() -> f64.Event::Resizednow means the size or the scale changed.The winit fork gets one commit appended to
toyos-0.30.13:scale_factor()answers the window's scale.ScaleFactorChangedand thenResized.LogicalSizegoes on the wire as it is. APhysicalSizegoes as logical at 1.0, as the Wayland backend does.InnerSizeWriter's answer is not honoured, asrequest_inner_sizeis not today: the compositor decides window sizes.The compositor draws at scale:
Chromemetric ispx(DEFAULT). The desk, back buffer, wallpaper and window budget follow, as they do on a mode change today.toyos-fontrasterizes JetBrains Mono from its TTF into a cell ofpx(8)xpx(16).build/assets.rs'srasterize_cells, moved into the crate, so the build and the guest share one producer.fontduebecomes a runtime dependency oftoyos-font. It is already inCargo.lockfor the build, calc and snake.spriterasterizes each SVG atpx(size), usingbuild/icons.rs's rasterizer moved into it, and the build ships the SVGs. That file's header promises "no program carries a rasterizer while no icon is drawn at a size the build did not know"; a scale is what ends that.px(20)fits virtio's 64x64, which is up to 3.2x. Past that the cursor is drawn in software. The hotspot scales.Relayout is pure, in
toyos-desktop:n'/nand is then reflowed onto the work area.Nothing flashes.
ToyOS's own clients render at scale.
Fontat the scale, and their layout constants throughpx.inspect displaygainsscale.Roast.
n/120, so finer steps would be a policy change, not a wire change.LogicalSize<f64>. A fractional-scale-v1 client avoids that, at the cost of a rounding contract across the wire, which ToyOS then does not need.round(round(x·a)/a)is exact fora ≥ 1but not fora < 1.PhysicalSize. At 1.25 they open larger with text the same size, as they do on a Retina Mac today. Fixing them is their job, not the platform's.MSG_SET_RESOLUTION's today. Any program that holds the connector can change both.Checks.
Host:
lib/edid:Its fixtures are QEMU 11.1.1's four EDIDs, committed with the commands that made them (above), and M1's panels.
Scale:relayout:
the window's buffer swap: at most two buffers, and the old one dropped at the first present after a resize.
Guest: the whole suite, at scale 1, which QEMU's EDID gives it. No new guest test.
Metal:
inspect displayon each laptop, reading the scale its EDID gives.No row: nothing is timed.
Negative control:
ab655a115;Oracle:
Metal, now and later
8086:9A49(issues/toyos-has-a-desktop.md), on the firmware's GOP at the panel's 1920x1080.1002:1637. Its GPU's id, its panel and its GOP mode are not in the tree.issues/gop-is-not-the-path-every-boot-takes.md), and the kernel makes no UEFI call after the loader.issues/tearing-is-what-gop-cannot-give-back.md).Displayas another variant, bringing EDID over the panel's own link, a mode list, flips on vblank, and hotplug interrupts.What I am unsure of
max_hostmemholds a pair at that size with under 3 MB to spare.HOME, or/configbeside the keyboard layout. The layout is in/configbecause every translator reads it; the scale has one reader._DDC) are from memory. Those pages could not be fetched, and each is checked against the standard and cited at its site before the build.Gates
Design round: nothing built, and no gate run.
git diff --shortstat origin/main...HEADis empty.🤖 Generated with Claude Code
https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy