57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 1 | # wry backend research reports |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 2 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 3 | Raw reader reports on wry (jay fork) internals, gathered for monolith planning. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 4 | Paths are relative to `/home/bolt/code/wry` at `6df16858`. Wry forked from jay at `f73b4efe` (2026-08-16). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 5 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 6 | Status |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 7 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 8 | - [x] Executor core (`src/async_engine*`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 9 | - [x] io_uring, timers, cpu_worker, task usage |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 10 | - [x] DRM/KMS metal backend and frame scheduling |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 11 | - [x] Wire protocol and client handling |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 12 | - [x] Vulkan renderer |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 13 | - [x] Tree, transactions, multiphase animations |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 14 | - [x] Process model, config, tests, utilities |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 15 | - [x] Smithay extension points (comparison baseline) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 16 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 17 | --- |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 18 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 19 | ## 0. Executor core |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 20 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 21 | `src/async_engine.rs`, `src/async_engine/ae_task.rs`, `src/async_engine/ae_yield.rs`, about 500 lines total. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 22 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 23 | - Single threaded, `Rc` based, nothing is `Send`. Wakers use a custom `RawWakerVTable` with a non-atomic refcount (`NumCell`), so a waker crossing threads would be UB. The cpu_worker bridges threads with eventfds instead. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 24 | - One `Box<Task>` allocation per spawn. A wake pushes a two-word `Runnable` onto a `VecDeque`. No atomics or locks anywhere on the wake path. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 25 | - Task state is a bitset (`RUNNING`, `RUN_AGAIN`, `COMPLETED`, `EMPTIED`, `CANCELLED`). A wake while running sets `RUN_AGAIN` instead of double-queueing. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 26 | - Dropping the returned `SpawnedFuture` cancels the task, so lifetimes are structured by ownership. Awaiting it yields the task's output. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 27 | - Four ordered phases, `EventHandling`, `Layout`, `PostLayout`, `Present`. `dispatch()` drains phase 0 to a fixpoint, then phase 1, and so on. Work woken into an earlier phase by a later one waits for the next pass. After all phases the iteration counter bumps and `yield_now()` waiters wake. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 28 | - `now()` / `now_rt()` are cached per pass, so everything in one pass sees the same timestamp. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 29 | - `spawn` defaults to `EventHandling`. `spawn2` pins a phase. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 30 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 31 | How the phases are used (`src/compositor.rs:598-745`). About 38 long-lived global tasks follow a dirty-queue pattern. Example `container_layout` (`src/tree/container.rs:2706`) loops on `state.pending_container_layout.pop().await` and checks a `layout_scheduled` flag. The task lives in `Phase::Layout`, so any number of requests that dirty a container during event handling collapse into one layout pass. The same pattern drives render positions, title textures, output render data, popup positioning, tree serial groups, configurables (all `PostLayout`), and screencast and present loops (`Present`). Client send tasks are `PostLayout` (`src/client/tasks.rs:27`), so events generated during a pass are flushed once after layout. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 32 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 33 | --- |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 34 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 35 | ## 1. io_uring, timers, cpu_worker, task usage |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 36 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 37 | ### 1.1 io_uring layer (`src/io_uring.rs`, `src/io_uring/ops/`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 38 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 39 | Opcodes wrapped, one module each (`src/io_uring/ops.rs:4-19`). `READ`/`WRITE` (`ops/read_write.rs:18-30`), `READ`/`WRITE` no-cancel with explicit offset (`ops/read_write_no_cancel.rs:21-58`), `WRITE` vec (`ops/read_write_vec.rs:29-86`), `WRITEV` (`ops/writev_external.rs:25-47`), `RECVMSG` (`ops/recvmsg.rs:18-83`), `SENDMSG` (`ops/sendmsg.rs:22-85`), `POLL_ADD` (`ops/poll.rs:17-42`, external callback variant `ops/poll_external.rs:35-74`), `TIMEOUT` (`ops/timeout.rs:28-44`, external `ops/timeout_external.rs:49-73`), `LINK_TIMEOUT` (`ops/timeout_link.rs:18-29`), `ACCEPT` (`ops/accept.rs:15-37`), `CONNECT` (`ops/connect.rs:19-39`), `ASYNC_CANCEL` (`ops/async_cancel.rs:16-24`), `FUTEX_WAIT`/`FUTEX_WAKE` (`ops/futex.rs:33-75`), `READ_MULTISHOT` (`ops/read_multishot.rs:49-77`). A provided buffer-ring helper exists (`buffer_ring.rs:79-173`) but outside tests is only wired to multishot reads. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 40 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 41 | Setup has no `SQPOLL` and no registered fds/buffers on the hot path. `IoUring::new` tries `SUBMIT_ALL|COOP_TASKRUN|SINGLE_ISSUER|DEFER_TASKRUN` then drops one flag at a time on `ENOSYS` (`src/io_uring.rs:131-154`), and hard-requires `NODROP` (`src/io_uring.rs:155-157`). Rings are `mmap`ed directly, queue depth 32 on both main and worker rings (`src/compositor.rs:276`, `src/cpu_worker.rs:367`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 42 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 43 | Submit. `encode` (`src/io_uring.rs:488-525`) drains `to_encode` into the SQ while space remains, reserves two slots for `has_timeout` ops, and sets `IOSQE_IO_LINK` on the parent so the following `LINK_TIMEOUT` fires as a link (`src/io_uring.rs:516-518`, `ops/timeout_link.rs:40-46`). Used by `write` and `sendmsg` with absolute `Time` (`ops/read_write.rs:32-61`, `ops/sendmsg.rs:74-83`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 44 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 45 | Enter/wait. `run` (`src/io_uring.rs:400-453`) is the only blocking point. An empty queue submits `0` and waits for `1` with `GETEVENTS`. Pending submits with empty `to_encode` submit `to_submit` and wait for `1`. Non-empty `to_encode` submits `u32::MAX` with no wait and loops to encode more (`src/io_uring.rs:417-424`). `yields` force `min_complete=0` (`src/io_uring.rs:425-427`). `EAGAIN|EBUSY|EINTR` are ignored, other `enter` errors are fatal (`src/io_uring.rs:438-443`). A short submit retries with a pure wait (`src/io_uring.rs:444-451`). On teardown `kill` encodes, submits `u32::MAX`, then waits until `tasks` empties (`src/io_uring.rs:594-617`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 46 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 47 | Wakeup. Almost every awaitable op takes `pending_results.acquire()` (`src/io_uring/pending_result.rs:21-37`), stores a clone in the task, schedules a pooled task struct, and awaits it (e.g. `ops/read_write.rs:40-60`). `dispatch_completions` matches `user_data` to the task, with `CQE_F_MORE` routed to `complete_partial` for multishot and terminal CQEs routed to `task.complete` (`src/io_uring.rs:455-486`). `PendingResult::complete` stores `res` and wakes the `Waker` (`src/io_uring/pending_result.rs:66-74`). `poll` translates negative `res` to `OsError` (`src/io_uring/pending_result.rs:105-122`). Non-`Future` completions use `PollCallback`, `TimeoutCallback`, `WritevData::done`, `ReadMultishotCallback` (`ops/poll_external.rs:15-17`, `ops/timeout_external.rs:16-18`, `ops/writev_external.rs:20-24`, `ops/read_multishot.rs:28-31`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 48 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 49 | Cancel. Dropping an op future cancels it, because the future owns a `Cancellable` whose `Drop` calls `cancel_task` (`src/io_uring.rs:527-544`, `src/io_uring.rs:640-644`). Not-yet-encoded ops complete locally with synthetic `ECANCELED` (`src/io_uring.rs:542-554`). In-kernel ops get an `ASYNC_CANCEL` by `user_data` (`ops/async_cancel.rs:16-24`, `ops/async_cancel.rs:41-44`). `is_cancel` tasks are exempt from `kill` cancellation (`src/io_uring.rs:596-604`). `PendingPoll`, `PendingTimeout`, `PendingReadMultishot` `Drop` impls do the same (`ops/poll_external.rs:25-33`, `ops/timeout_external.rs:26-34`, `ops/read_multishot.rs:39-47`). `read/write_no_cancel` instead forbids userspace cancel with an `on_drop` panic guard, for worker-thread shm I/O (`ops/read_write_no_cancel.rs:92-96`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 50 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 51 | No epoll fallback. `CreateUring`/`NoDrop` become `CompositorError::IoUringError` and exit (`src/io_uring.rs:96-102`, `src/compositor.rs:227-241`, `src/compositor.rs:275-276`). Grep finds no epoll/calloop fallback. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 52 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 53 | ### 1.2 Main loop, one iteration (`src/io_uring.rs:400-453`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 54 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 55 | Bump `iteration`, wake `yields` wakers, then loop `eng.dispatch()` plus `dispatch_completions()` until no more CQEs were consumed. Then `encode()` queued SQEs, accumulating `to_submit`, then one `io_uring_enter` with the wait policy above. Startup order is engine, ring 32, signal handler, wheel, run-toplevel, cpu worker, eventfd cache, then `ring.run()` (`src/compositor.rs:275-286`, `src/compositor.rs:530-535`). The `compositor` future only runs backend setup. Blocking lives in the ring (`src/compositor.rs:538-588`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 56 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 57 | Unusual. Ready futures are drained to quiescence before entering the kernel, and `Debouncer` plus `yields` let hot paths skip the blocking wait (`src/io_uring/debounce.rs:15-34`, `src/io_uring.rs:425-427`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 58 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 59 | ### 1.3 Timers |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 60 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 61 | `wheel.rs` is a single-`timerfd`, heap-multiplexed wheel (`src/wheel.rs:102-114`). `Wheel::new` creates a `CLOCK_MONOTONIC` `timerfd` and spawns `dispatch` (`src/wheel.rs:117-137`). `timeout(ms)` rounds to ms, re-arms with `TFD_TIMER_ABSTIME` only if earlier than the armed expiry, pushes `{expiration,id}` on a `BinaryHeap`, and registers the waiter (`src/wheel.rs:156-194`, `src/time.rs:34-46`). `dispatch_once` does `ring.read(timerfd)` then completes every due entry and re-arms to the next live entry, skipping cancelled ids (`src/wheel.rs:218-254`). Waiters are manual `Future`s storing a `Waker` (`src/wheel.rs:65-100`). `Drop` unregisters and recycles (`src/wheel.rs:78-87`). Consumers include client shutdown 5s (`src/client/tasks.rs:35`) and cursor tick (`src/tasks/hardware_cursor.rs:17-22`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 62 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 63 | Separately, `TimerFd::expired` is `ring.read(timerfd)` plus `timerfd_settime` programming (`src/utils/timer.rs:42-67`), used by idle, 40Hz latch, damage, config, virtual-output (`src/tasks/idle.rs:14-20`, `src/tasks/const_clock.rs:19-35`, `src/virtual_output.rs:731`). Raw `ring.timeout(nsec)` with `IORING_TIMEOUT_ABS` is used for present/vblank, transactions, sqlite, session (`src/io_uring/ops/timeout.rs:27-44`, `src/virtual_output.rs:475`, `src/output_schedule.rs:172-174`, `src/transactions.rs:453`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 64 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 65 | ### 1.4 cpu_worker (`src/cpu_worker.rs`, `src/cpu_worker/jobs/`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 66 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 67 | One background thread named `cpu worker` with its own `AsyncEngine` plus ring depth 32 (`src/cpu_worker.rs:275-294`, `src/cpu_worker.rs:366-386`). `CpuJob::work` returns the thread-side `CpuWork`, and `completed` runs back on the main thread (`src/cpu_worker.rs:33-50`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 68 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 69 | Main submits with `submit`, leaking the job box and queueing `Job::New{id, *mut dyn CpuWork}` on an `AsyncQueue`, returning a `PendingJob` (`src/cpu_worker.rs:323-339`). An `equeue_jobs` task moves it under lock to the shared `VecDeque` and writes the `have_new_jobs` eventfd (`src/cpu_worker.rs:249-261`). The worker `ring.read`s that eventfd and runs `CpuWork::run`. `None` completes synchronously, `Some(AsyncCpuWork)` is spawned on the worker engine until `WorkCompletion::complete` (`src/cpu_worker.rs:425-473`, `src/cpu_worker.rs:68-77`). Completion pushes the id to the shared completed queue, signals a condvar for sync waiters, and writes `have_completed_jobs` (`src/cpu_worker.rs:475-487`). The main `wait_for_completions` task `ring.read`s it and invokes `job.completed()` (`src/cpu_worker.rs:216-247`). Dropping a pending job warns, sends `Job::Cancel`, and blocks dispatching until gone. `detach` marks it abandoned (`src/cpu_worker.rs:151-204`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 70 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 71 | Call sites, all via `cpu.submit`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 72 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 73 | - `CloseMemWork`, munmap off-thread, detached (`src/clientmem.rs:211-215`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 74 | - Text `RenderJob` (`src/text.rs:528`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 75 | - Vulkan allocator `FreeJob` and `AllocJob` (`src/gfx_apis/vulkan/allocator.rs:185`, `src/gfx_apis/vulkan/allocator.rs:303`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 76 | - shm transfers, `ImgCopyWork` for pointer-backed and `ReadWriteWork` for fd-backed mem (`src/gfx_apis/vulkan/transfer.rs:505`, `src/gfx_apis/vulkan/transfer.rs:539`, `src/cpu_worker/jobs/img_copy.rs:32-59`, `src/cpu_worker/jobs/read_write.rs:98-148`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 77 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 78 | ### 1.5 eventfd_cache (`src/eventfd_cache.rs`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 79 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 80 | Avoids `eventfd()` churn and forgotten counter drains. Pools fds, `signaled` bools, and `Readable` callback objects (`src/eventfd_cache.rs:39-45`), with a `recycle` task spawned at creation (`src/eventfd_cache.rs:64-75`). `acquire` reuses or creates (`src/eventfd_cache.rs:77-89`). Async wait is `ring.readable` (`src/eventfd_cache.rs:97-104`). External wait reuses a pooled `Readable` through `readable_external` (`src/eventfd_cache.rs:120-137`). `Drop` of a still-signaled fd pushes it to `recycle`, which `ring.read`s each fd empty before returning it to the pool (`src/eventfd_cache.rs:156-224`). `return_signaled` recycles the bool only when the cache holds the last ref (`src/eventfd_cache.rs:208-215`). Held by `State` and passed to the copy-device registry (`src/compositor.rs:466-469`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 81 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 82 | ### 1.6 Long-lived tasks in `src/tasks/` |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 83 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 84 | - `handle_backend_events`, demuxes the backend queue into connector/input/drm handlers (`src/tasks.rs:22-25`, `src/tasks/backend.rs:12-28`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 85 | - `handle_slow_clients` / `handle_slow_ei_clients`, backpressure kills via `check_queue_size` (`src/tasks.rs:27-35`, `src/tasks/slow_clients.rs:8-28`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 86 | - `handle_const_40hz_latch`, dummy-output latch clock (`src/tasks.rs:37-44`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 87 | - Per-connector `ConnectorHandler`, output lifecycle (`src/tasks/connector.rs:92-98`, `src/tasks/connector.rs:113-141`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 88 | - Per-DRM-device handler (`src/tasks/drmdev.rs:74`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 89 | - Per-input-device handler (`src/tasks/input_device.rs:48-58`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 90 | - `idle`, `TimerFd`-driven DPMS/idle state machine (`src/tasks/idle.rs:13-32`, `src/compositor.rs:651`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 91 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 92 | ### 1.7 Spawn survey |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 93 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 94 | `eng.spawn`/`spawn2` has 175 hits in 64 files. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 95 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 96 | - `start_global_event_handlers` alone spawns about 38 named globals covering backend events, slow clients, cursor tick, layout, render positions/titles/textures, output render, managers, idle, popups, screencast, damage, matchers, seats, sqlite, sessions, transactions (`src/compositor.rs:598-745`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 97 | - Per client, 3 tasks per Wayland client plus 2-3 per EI client (`src/client/tasks.rs:20-28`, `src/ei/ei_client/ei_tasks.rs:21-27`, `src/client.rs:258-260`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 98 | - Acceptors/listeners are async accept loops, Wayland secure and insecure, IPC, tagged, security-context, EI (`src/acceptor.rs:144-153`, `src/acceptor.rs:168-191`, `src/ipc.rs:114`, `src/tagged_acceptor.rs:84`, `src/security_context_acceptor.rs:90-95`, `src/ei/ei_acceptor.rs:124`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 99 | - Protocol I/O is async everywhere. dbus auth/in/out, pipewire in/out, forker in/out, xcon in/out, tool clients (`src/dbus/auth.rs:45-50`, `src/pipewire/pw_con.rs:356-359`, `src/forker.rs:123-135`, `src/xcon.rs:469-522`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 100 | - Xwayland is `xwayland::manage` plus `XWM` plus per-transfer shm copy tasks (`src/state.rs:1636`, `src/xwayland.rs:219`, `src/xwayland/xwm.rs:1788-1901`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 101 | - Rendering/output is phased `spawn2` layout/present work plus per-output schedule, vblank, virtual-output, backend event/present tasks (`src/compositor.rs:611-680`, `src/tasks/connector.rs:186-189`, `src/virtual_output.rs:1023-1024`, `src/backends/x.rs:359-364`, `src/backends/metal/video.rs:1221`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 102 | - Vulkan transfer/vblank await tasks are also spawned (`src/gfx_apis/vulkan/transfer.rs:582-627`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 103 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 104 | Rough split of non-test spawns. Client/EI/IPC/dbus/pipewire about 35, render/layout/output/present about 45, backend/connector/DRM/input/seat about 15, xwayland/X11 about 8, global compositor/timer/sqlite/config about 25. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 105 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 106 | ### 1.8 Client sockets |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 107 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 108 | One supervisor plus receive, send, terminate tasks per client (`src/client/tasks.rs:18-44`). Receive parses with `WlBufFdIn` over `ring.recvmsg`, including SCM_RIGHTS fds (`src/client/tasks.rs:59-93`, `src/utils/buffd/wl_buf_in.rs:52-126`). Send buffers into `OutBufferSwapchain`. `commit` moves a non-empty `cur` to `pending`, and the send task waits on `flush_request`, swaps `pending` out, and `BufFdOut::flush`es each buffer with an absolute 5s `sendmsg` linked timeout (`src/client/tasks.rs:112-147`, `src/utils/buffd/buf_out.rs:57-91`, `src/utils/buffd/buf_out.rs:102-131`, `src/io_uring/ops/sendmsg.rs:32-85`). `ECANCELED` becomes `Timeout`, `EPIPE`/`ECONNRESET` become `Closed` (`src/utils/buffd/buf_out.rs:121-130`). Slow clients are reaped when `pending` exceeds 10 (`src/utils/buffd/buf_out.rs:48-59`, `src/client.rs:520`). Direct `recvmsg`/`sendmsg` with no userspace epoll shim. Generic bidirectional connections use the same pair through `BufIo` (`src/utils/bufio.rs:101-114`, `src/utils/bufio.rs:143-179`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 109 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 110 | Notable vs calloop. Everything above plus pooled task structs, `PendingResult` slab recycling raw pointers, link-timeouts instead of timer races, and a second full runtime on the worker thread. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 111 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 112 | --- |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 113 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 114 | ## 2. DRM/KMS metal backend and frame scheduling |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 115 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 116 | ### 2.1 KMS model |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 117 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 118 | Atomic only. Device init enables `DRM_CLIENT_CAP_ATOMIC` with value 2 and then probes resources, planes, CRTCs, encoders (`src/backends/metal/video.rs:2030`, `src/backends/metal/video.rs:2032`, `src/backends/metal/video.rs:2040`). It also tries `DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE` and records support (`src/backends/metal/video.rs:2035`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 119 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 120 | Desired state is `BackendConnectorState` in `backend.rs` (`src/backend.rs:785`). Committed DRM state is split into `DrmPlaneState`, `DrmCrtcState`, `DrmConnectorState` plus property structs in transaction (`src/backends/metal/transaction.rs:71`). `create_transaction` clones live `drm_state` for every non-leased plane, CRTC and connector and stores requested connector state separately (`src/backends/metal/transaction.rs:221`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 121 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 122 | `calculate_drm_state` assigns CRTCs, primary and cursor planes, checks formats and modifiers, allocates scanout buffers when needed, and picks modes, VRR, tearing, colorspace, EOTF and HDR blobs (`src/backends/metal/transaction.rs:314`). `calculate_change` diffs new property structs against live objects with `differs` and `prepare_conditional` and only emits changed objects (`src/backends/metal/transaction.rs:902`, `src/backends/metal/transaction.rs:928`, `src/backends/metal/transaction.rs:949`). It also resets unknown or vendor default properties when asked (`src/backends/metal/transaction.rs:874`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 123 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 124 | `TEST_ONLY` is used in the prepare path. `MetalDeviceTransaction::prepare` calls `calculate_drm_state` then `calculate_change(true,false)` (`src/backends/metal/transaction.rs:1216`). When test is true it calls `Change::test` with `DRM_MODE_ATOMIC_ALLOW_MODESET`, which adds `DRM_MODE_ATOMIC_TEST_ONLY` in `video/drm.rs` (`src/backends/metal/transaction.rs:982`, `src/video/drm.rs:1097`). Failure surfaces as `AtomicTestFailed` (`src/backend/transaction.rs:124`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 125 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 126 | Normal apply first commits with flags 0 then retries once with `ALLOW_MODESET` after logging (`src/backends/metal/transaction.rs:993`). After a successful kernel commit it swaps new state into live `drm_state`, connector, CRTC and plane objects with `mem::swap` and bumps the connector version (`src/backends/metal/transaction.rs:1092`, `src/backends/metal/transaction.rs:1100`). Rollback keeps the pre-apply state and reapplies it with `calculate_change(false,false)` (`src/backends/metal/transaction.rs:1194`). The generic wrapper also rolls back on drop (`src/backend/transaction.rs:248`). Device init has an extra recovery loop that retries init while disabling direct scanout, non-XRGB formats and non-default modes (`src/backends/metal/video.rs:2553`, `src/backends/metal/video.rs:2589`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 127 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 128 | ### 2.2 Planes |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 129 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 130 | Types are `Overlay`, `Primary` and `Cursor` (`src/backends/metal/video.rs:1023`). The transaction carries `primary` plus `cursor` per CRTC (`src/backends/metal/transaction.rs:283`). Overlay planes are explicitly discarded during assignment, so compositing uses at most primary plus cursor (`src/backends/metal/transaction.rs:360`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 131 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 132 | Cursor uses fixed `ARGB8888` (`src/backends/metal/transaction.rs:281`) and separate double-buffered cursor scanout buffers (`src/backends/metal/video.rs:628`). Cursor enable, move and swap produce `CursorProgrammingType::Enable` or `Disable` (`src/backends/metal/present.rs:127`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 133 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 134 | Direct scanout puts a client dmabuf on the primary plane through `add_fb` instead of the compositor render buffer. It is attempted only when enabled and when `prepare_direct_scanout` succeeds (`src/backends/metal/present.rs:901`). That path rejects cross-device buffers unless the scanout device is the render device, rejects SHM, rejects buffers with pending lazy work, checks plane format and modifier support, and caches failures by a key of buffer ID, plane, CRTC, source and destination color descriptions, intent, gamma, cursor presence and pipeline mode (`src/backends/metal/present.rs:746`, `src/backends/metal/present.rs:778`, `src/backends/metal/present.rs:845`). A failed atomic commit with direct scanout retries once as a full composite and then marks that key impossible (`src/backends/metal/present.rs:337`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 135 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 136 | ### 2.3 Frame scheduling |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 137 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 138 | Each connector spawns its own `present_loop` in phase `Present` (`src/backends/metal/video.rs:1220`). Page flip events arrive on a per-device task that awaits `DrmMaster::event`, which does an io_uring read on the DRM fd and parses `DRM_EVENT_FLIP_COMPLETE` and `DRM_EVENT_CRTC_SEQUENCE` (`src/backends/metal/video.rs:2268`, `src/video/drm.rs:590`, `src/video/drm.rs:607`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 139 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 140 | The loop waits for `present_trigger` then requires both `buffers_idle` and `crtc_idle` (`src/backends/metal/present.rs:189`). For synced flips it computes `next_vblank - pre_commit_margin - post_commit_margin` and sleeps with `ring.timeout` until that deadline (`src/backends/metal/present.rs:203`). If already past the deadline it increments the expected sequence so a missed vblank can be detected (`src/backends/metal/present.rs:210`). Tearing flips skip that wait (`src/backends/metal/present.rs:203`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 141 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 142 | It then calls `before_latch` with either now for tearing or `next_vblank_nsec` for synced output (`src/backends/metal/present.rs:218`). It aborts if the connector version changed while yielding (`src/backends/metal/present.rs:226`). Then `present_once` latches damage, renders or selects direct scanout, waits render then scanout fences, programs the atomic commit, and on success marks CRTC busy and buffers busy (`src/backends/metal/present.rs:250`, `src/backends/metal/present.rs:314`, `src/backends/metal/present.rs:387`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 143 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 144 | `pre_commit_margin` starts at 16ms and `post_commit_margin` starts at 1.5ms (`src/backends/metal/present.rs:145`). The pre margin tracks the per-second maximum CPU time from wakeup through latch with a geometric decay of 0.5 (`src/backends/metal/present.rs:238`, `src/backends/metal/video.rs:1208`). The post margin grows by 500us per second containing missed flips and decays toward the device minimum otherwise (`src/backends/metal/present.rs:147`, `src/backends/metal/video.rs:2425`). Expected versus actual CRTC sequence decides misses (`src/backends/metal/video.rs:2378`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 145 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 146 | Flip completion clears `pending_flip`, promotes `next_framebuffer` to `active_framebuffer`, sets `buffers_idle`, emits presentation feedback with `HW_COMPLETION` plus `VSYNC` and `ZERO_COPY` when applicable, then sets `crtc_idle` and reschedules if damage remains (`src/backends/metal/video.rs:2368`, `src/backends/metal/video.rs:2387`, `src/backends/metal/video.rs:2406`). It also maintains `next_vblank_nsec` from flip timestamps plus refresh interval and continuously queues `CRTC_SEQUENCE` for vblank timing unless emulation is active (`src/backends/metal/video.rs:2347`, `src/backends/metal/video.rs:2418`, `src/backends/metal/video.rs:867`). If queueing sequences returns `EOPNOTSUPP` it switches that output to vblank emulation (`src/backends/metal/video.rs:881`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 147 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 148 | `output_schedule.rs` is separate from that pacing loop. It only throttles cursor updates in VRR mode. `latched` records present time and clears awaiting-latch flags (`src/output_schedule.rs:100`). `run_once` sleeps until `last_present + cursor_delta` when VRR plus a cursor change is pending, then damages either the hardware cursor or the connector (`src/output_schedule.rs:157`, `src/output_schedule.rs:187`). Tree latch plumbing calls `schedule.latched` from `OutputNode::latched` (`src/tree/output.rs:355`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 149 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 150 | ### 2.4 VRR and tearing |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 151 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 152 | State carries `vrr` and `tearing` booleans (`src/backend.rs:792`). The transaction rejects VRR on connectors without `vrr_capable` and rejects tearing without atomic async flip support (`src/backends/metal/transaction.rs:766`, `src/backends/metal/transaction.rs:772`). `vrr_capable` comes from the `vrr_capable` property (`src/backends/metal/video.rs:1423`) and async support comes from `DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP` (`src/video/drm.rs:404`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 153 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 154 | Per-frame tearing is `persistent tearing AND supports_async_commit` (`src/backends/metal/present.rs:442`). The atomic commit first tries `NONBLOCK | EVENT | ASYNC`, and on failure falls back to synced `NONBLOCK | EVENT` while also attaching `IN_FENCE_FD` and requesting `OUT_FENCE_PTR` except on Nvidia (`src/backends/metal/present.rs:572`, `src/backends/metal/present.rs:581`). Any plane geometry change or cursor plane change forces the synced path (`src/backends/metal/present.rs:493`, `src/backends/metal/present.rs:516`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 155 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 156 | ### 2.5 Color management |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 157 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 158 | `metal_cm` selects a KMS programming for each frame from source and destination `ColorDescription` values plus render intent, gamma LUT, cursor presence and pipeline selection (`src/backends/metal/video/metal_cm.rs:100`). It caches programmings, matcher results and blobs (`src/backends/metal/video/metal_cm.rs:60`). A programming can set plane `COLOR_PIPELINE`, plane colorop bypass, type, interpolation, data and multiplier, and CRTC gamma LUT (`src/backends/metal/video/metal_cm.rs:127`, `src/backends/metal/video/metal_cm.rs:138`, `src/backends/metal/video/metal_cm.rs:153`). Matching logic decides whether matrix, source EOTF, destination EOTF or client gamma are needed (`src/backends/metal/video/metal_cm/metal_cm_matcher.rs:124`). The minimum LUT size considered useful is 1024 (`src/backends/metal/video/metal_cm.rs:54`). On AMD with a cursor plane it disables plane pipelines as a driver workaround (`src/backends/metal/video/metal_cm.rs:185`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 159 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 160 | `metal_cm_paths/generated.rs` holds generated static tables of `PlaneOpKind`, matrix, LUT and multiply variants used by the matcher (`src/backends/metal/video/metal_cm/metal_cm_paths/generated.rs:12`). The handwritten wrapper defines `Path`, plane and CRTC op accessors and criteria filters (`src/backends/metal/video/metal_cm/metal_cm_paths.rs:15`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 161 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 162 | Legacy properties are also handled. CRTC defaults include `CTM`, `DEGAMMA_LUT`, `OUT_FENCE_PTR` and AMD regamma (`src/backends/metal/video.rs:1565`). Plane defaults include AMD blend, shaper, 3D LUT, HDR multiplier, alpha, blend mode, rotation and `COLOR_PIPELINE Bypass` for non-primary planes (`src/backends/metal/video.rs:1680`). Plane pipeline use is opt-in through `use_plane_color_pipelines`, default false (`src/backends/metal/video.rs:2123`, `src/backend.rs:672`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 163 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 164 | HDR uses connector `Colorspace` and `HDR_OUTPUT_METADATA` plus EDID-derived PQ and BT2020 support, primaries and luminance (`src/backends/metal/video.rs:1351`, `src/backends/metal/video.rs:1452`, `src/backends/metal/video.rs:1500`). The transaction creates the HDR metadata blob from EOTF, primaries and luminance (`src/backends/metal/transaction.rs:802`, `src/video/drm.rs:919`). The renderer supplies `cd`, linear and blend descriptions per frame, and `metal_cm` maps framebuffer description to output description (`src/backends/metal/present.rs:277`, `src/backends/metal/present.rs:889`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 165 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 166 | ### 2.6 Allocator and multi-GPU |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 167 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 168 | Allocation is GBM based, not dumb buffers. It creates render and scanout `GbmBo` objects, imports them as gfx textures and framebuffers, and registers display framebuffers with `add_fb2` (`src/backends/metal/allocator.rs:878`, `src/backends/metal/allocator.rs:914`, `src/video/drm.rs:441`). GEM handles are cached (`src/video/drm.rs:484`). Modifier lists come from the plane `IN_FORMATS` blob, with fallback to the legacy plane format list (`src/backends/metal/video.rs:1616`, `src/video/drm.rs:531`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 169 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 170 | Same-GPU scanout uses one BO for render and scanout (`src/backends/metal/allocator.rs:454`). Cross-GPU tries configurable prime methods in order `direct-pull`, `direct-push`, `udmabuf`, `direct-sampling` and `indirect-pull`, controlled by `WRY_PRIME_METHODS` (`src/backends/metal/allocator.rs:464`, `src/backends/metal/allocator.rs:615`, `src/backends/metal/allocator.rs:1528`). Each method intersects render write and read modifiers, plane modifiers and copy device source and destination modifiers, with copy paths forced to linear when available (`src/backends/metal/allocator.rs:1224`, `src/backends/metal/allocator.rs:1595`). Buffer kinds are direct sampling versus three copy device topologies plus direct push, which is noted as unsafe on AMD (`src/backends/metal/allocator.rs:85`, `src/backends/metal/allocator.rs:621`). Per-frame `copy_to_dev` performs the needed GPU or copy device transfer (`src/backends/metal/allocator.rs:154`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 171 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 172 | ### 2.7 Hotplug, session, lease |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 173 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 174 | Hotplug watches `drm` and `input` through udev (`src/backends/metal.rs:307`). A task waits for the monitor fd with io_uring readable readiness and dispatches add versus change (`src/backends/metal/monitor.rs:42`). DRM change diffs kernel connectors against known connectors, emits `Disconnected` plus `Removed`, revokes affected leases, refreshes properties and display data, creates new connector objects and reinitializes the device (`src/backends/metal/video.rs:1844`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 175 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 176 | Logind handling takes session control, takes each device fd, and installs pause and resume handlers (`src/backends/metal.rs:295`, `src/logind.rs:76`, `src/backends/metal/monitor.rs:402`). Pause marks the DRM device paused, hides non-desktop outputs and parks leases in `leases_to_break` (`src/backends/metal/monitor.rs:166`). Resume clears paused state, retries lease revocation, refreshes properties and reschedules presents (`src/backends/metal/monitor.rs:97`, `src/backends/metal/video.rs:2248`). Losing DRM master surfaces as `EACCES` on commit and is intentionally ignored per frame (`src/backends/metal/present.rs:379`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 177 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 178 | Leases are supported for non-desktop outputs. Creation requires connected non-desktop connectors, allocates an unused CRTC and primary plane per connector, calls the kernel lease ioctl and emits `Unavailable` (`src/backends/metal/video.rs:264`, `src/video/drm.rs:638`). Dropping the lease object revokes it or parks it for later revocation and makes the connector available again (`src/backends/metal/video.rs:550`, `src/backends/metal/video.rs:514`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 179 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 180 | ### 2.8 Unusual choices |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 181 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 182 | - Overlays are enumerated but never assigned, unlike many compositors (`src/backends/metal/transaction.rs:360`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 183 | - Direct scanout participates in color pipeline search and has its own impossible-cache (`src/backends/metal/present.rs:778`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 184 | - Frame timing uses two adaptive margins rather than a fixed deadline, with the pre margin from measured CPU time and the post margin from missed sequence counts (`src/backends/metal/present.rs:238`, `src/backends/metal/video.rs:2425`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 185 | - The modeset path blocks on buffer clear and copy syncs inside transaction calculation and can synchronously poll a CRTC out fence before blanking (`src/backends/metal/transaction.rs:693`, `src/backends/metal/transaction.rs:843`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 186 | - Init and hotplug paths reset unknown KMS properties to driver defaults, which helps against firmware or desktop leftover state (`src/backends/metal/transaction.rs:886`, `src/backends/metal/video.rs:2589`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 187 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 188 | --- |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 189 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 190 | ## 3. Wire protocol and client handling |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 191 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 192 | ### 3.1 Protocol description format |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 193 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 194 | `wire/` holds a custom DSL, one file per interface. `wire/wl_surface.txt:1-8` shows `request destroy`, typed fields, `(destructor)`, `(since = 2)`, `(new)`. No XML is stored in tree. XML appears only at conversion boundaries. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 195 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 196 | The DSL parser lives in `build/wire/parser.rs:209-224` for `Type` with `Id, U32, I32, U64, U64Rev, Str, OptStr, BStr, Fixed, Fd, Bool, Array, Pod`, plus `build/wire/parser.rs:236-246` for `Message` and `build/wire/parser.rs:350-403` for message parsing. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 197 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 198 | `xml-to-wire/src/main.rs:9-14` plus `xml-to-wire/src/builder.rs:27-42` converts Wayland XML to `wire/*.txt`. Special handling maps `x_hi` plus `x_lo` pairs to `u64` or `u64_rev` (`xml-to-wire/src/builder.rs:83-106`) and maps untyped arrays or `dev_t` blobs to `array` or `pod` (`xml-to-wire/src/builder.rs:132-160`). `wire-to-xml/src/main.rs:41-60` does the reverse for debugging or interop. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 199 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 200 | The build script (`build/build.rs:53-67`) runs `wire::main` and emits to `OUT_DIR`. `build/wire.rs:497-539` scans `wire/`, parses every file, and writes `wire/mod.rs` plus one generated `wire/<iface>.rs` per interface. It also emits `id!` plus `Interface` constants (`build/wire.rs:455-494`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 201 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 202 | A generated request type is a plain struct with `self_id` plus fields (`build/wire.rs:57-76`). Its `RequestParser` impl is emitted in `build/wire.rs:78-202`. Fixed-size messages destructure `*parser.data()` directly (`build/wire.rs:112-170`). Variable-size messages call `parser.uint`, `str`, `bstr`, `fd`, `binary` and then `parser.eof` (`build/wire.rs:171-198`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 203 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 204 | A generated event writer implements `EventFormatter` (`build/wire.rs:203-302`). Fixed events use one `fmt.data` word array (`build/wire.rs:214-250`). Variable events use `fmt.header` plus per-field writers (`build/wire.rs:252-291`). Request and event handler traits are emitted together (`build/wire.rs:311-431`), with server traits using `Object` plus `Client` and client-side traits using `UsrObject` plus `UsrCon` (`build/wire.rs:327-348`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 205 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 206 | Parsing is largely zero-copy. `MsgParser` borrows the `&[u32]` body plus fd queue (`src/utils/buffd/parser.rs:33-47`). `str`, `bstr`, `array`, `binary_array` return borrowed `&str`, `&BStr`, `&[u8]`, `&[T]` (`src/utils/buffd/parser.rs:96-146`, `src/utils/buffd/parser.rs:159-176`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 207 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 208 | File descriptors travel as ancillary data. `WlBufFdIn` collects them with `recvmsg` (`src/utils/buffd/wl_buf_in.rs:110-126`). `MsgParser::fd` pops from that queue (`src/utils/buffd/parser.rs:122-127`). `MsgFormatter::fd` queues them and `write_len` records their message offset (`src/utils/buffd/formatter.rs:93-96`, `src/utils/buffd/formatter.rs:135-149`). Sending splits at fd boundaries (`src/utils/buffd/buf_out.rs:102-120`). This split-queue design is unusual relative to libwayland. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 209 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 210 | ### 3.2 Object model |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 211 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 212 | Each `Client` owns an `Objects` store (`src/client.rs:355`, `src/client/objects.rs:87-135`). There is one generic `registry` map plus many typed `CopyHashMap` maps for surfaces, buffers, seats and others (`src/client/objects.rs:88-134`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 213 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 214 | ID allocation splits the space at `MIN_SERVER_ID 0xff000000` (`src/client/objects.rs:137`). Client-created IDs must be nonzero and below that bound (`src/client/objects.rs:266-282`). Server IDs are allocated from a bitset freelist (`src/client/objects.rs:235-250`, `src/client/objects.rs:314-325`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 215 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 216 | Dispatch starts in the receive task. It reads `WlMessage obj_id message body fds` (`src/client/tasks.rs:64-72`), looks up the object (`src/client/tasks.rs:73-80`), then calls `handle_request` (`src/client/tasks.rs:81-90`). Every object forwards through `object_base!` to generated `handle_request_impl` (`src/macros.rs:41-66`). The generated dispatcher matches the opcode and emits a `version >= since` guard (`build/wire.rs:387-411`). Unknown opcodes become `InvalidMethod` (`build/wire.rs:413`, `src/client/error.rs:18-19`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 217 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 218 | Versioning is also enforced at bind time. `WlRegistry bind` checks interface name and `version <= global.version` (`src/ifs/wl_registry.rs:64-89`). Globals expose fixed versions, for example compositor version 7 (`src/ifs/wl_compositor.rs:82-86`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 219 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 220 | Protocol errors use `wl_display/error`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 221 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 222 | - Unknown objects trigger `send_invalid_object` plus shutdown (`src/client/tasks.rs:73-78`, `src/ifs/wl_display.rs:79-82`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 223 | - Unknown requests trigger `send_invalid_request` plus shutdown (`src/client.rs:394-416`, `src/ifs/wl_display.rs:68-77`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 224 | - Handler failures trigger `send_implementation_error` plus shutdown (`src/client/tasks.rs:94-108`, `src/ifs/wl_display.rs:84-86`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 225 | - Explicit `protocol_error` does the same (`src/client.rs:489-494`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 226 | - Method wrapping preserves interface, id, method and source error (`src/client/error.rs:35-42`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 227 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 228 | Lifetime uses `Rc` with explicit cycle breaking. `Object` has a default empty `break_loops` (`src/object.rs:25-27`). Client teardown calls `Objects::destroy`, which drains the generic registry through `break_loops` and clears typed maps (`src/client/objects.rs:186-233`). `ClientHolder Drop` drives that plus shutdown, activation token and timeline cleanup (`src/client.rs:320-337`). `WlSurface break_loops` drops children, dnd, cursors, transactions, feedback, viewporter and timelines (`src/ifs/wl_surface.rs:2104-2127`). Server ID removal can emit `delete_id` when symmetric deletion is active (`src/client/objects.rs:284-308`). Typed insertion and lookup go through `dedicated_add_obj!` (`src/macros.rs:341-361`), while simple objects and globals use `simple_add_obj!` and `simple_add_global!` (`src/macros.rs:363-373`). Explicit teardown instead of `Weak` everywhere is unusual relative to wayland-rs. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 229 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 230 | ### 3.3 Client I/O |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 231 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 232 | Input uses `WlBufFdIn` with an 8 KiB buffer and 4 KiB max message (`src/utils/buffd/wl_buf_in.rs:15-29`). It validates word alignment and `8 <= len <= 4096` (`src/utils/buffd/wl_buf_in.rs:69-77`), compacts unconsumed bytes (`src/utils/buffd/wl_buf_in.rs:100-108`), and caps queued fds at 32 (`src/utils/buffd/wl_buf_in.rs:122-124`). Error variants cover oversize, undersize, unaligned, missing and excess fds (`src/utils/buffd.rs:24-44`) with limits `BUF_SIZE 4096` and `MAX_IN_FD 32` (`src/utils/buffd.rs:46-47`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 233 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 234 | Output uses `OutBufferSwapchain` with current, pending and free buffers (`src/utils/buffd/buf_out.rs:50-69`). Each output buffer is 8 KiB and considered full past 4 KiB (`src/utils/buffd/buf_out.rs:14`, `src/utils/buffd/buf_out.rs:42-46`). `Client::event` formats into the current buffer, commits on full, then signals the sender (`src/client.rs:496-514`). The sender swaps pending buffers and flushes with a 5 second timeout (`src/client/tasks.rs:112-132`). Used buffers are recycled through `free` (`src/client/tasks.rs:128-131`, `src/utils/buffd/buf_out.rs:62-68`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 235 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 236 | Backpressure is bounded but not lossy for compliant clients. More than 10 pending buffers counts as over limit (`src/utils/buffd/buf_out.rs:57-60`). Over-limit clients enter the global slow queue once (`src/client.rs:505-511`). A background handler rechecks after a yield and kills still-slow clients (`src/client.rs:520-530`, `src/tasks/slow_clients.rs:9-14`). Event flushing is otherwise triggered, not synchronous after every request, as seen by the commented-out flush (`src/client/tasks.rs:91`) and trigger use (`src/client.rs:513`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 237 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 238 | ### 3.4 `clientmem.rs` |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 239 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 240 | SHM pools are mapped with `mmap64`, length rounded up to page size, with an empty mapping for zero length (`src/clientmem.rs:104-124`). Read-only pools use `PROT_READ`, writable pools add `PROT_WRITE`, normally `MAP_SHARED` (`src/clientmem.rs:78-123`). Private mappings are a separate constructor (`src/clientmem.rs:68-76`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 241 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 242 | Truncated client memory is handled with `SIGBUS`. Startup installs a `SA_SIGINFO` plus `SA_NODEFER` handler (`src/clientmem.rs:273-284`). Safe access pushes a thread-local record, runs the closure, then reports `Sigbus` if marked failed (`src/clientmem.rs:170-189`). The handler checks whether the fault address lies inside a tracked mapping (`src/clientmem.rs:241-254`), replaces that range with anonymous memory via `MAP_FIXED` (`src/clientmem.rs:255-262`), marks failure and returns (`src/clientmem.rs:266-267`), otherwise restores default and raises `SIGBUS` (`src/clientmem.rs:233-239`, `src/clientmem.rs:269`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 243 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 244 | Sealed memfds skip the handler path. If `F_SEAL_SHRINK` plus a large enough `st_size` is observed, the mapping is marked `sigbus_impossible` (`src/clientmem.rs:89-96`). It may first extend the file with `ftruncate` (`src/clientmem.rs:105-109`). Direct pointer access is allowed only in that case, otherwise callers get an fd plus offset (`src/clientmem.rs:319-324`). Destruction unmaps inline or offloads close plus unmap to the CPU worker (`src/clientmem.rs:207-222`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 245 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 246 | ### 3.5 `leaks.rs` |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 247 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 248 | `track!` registers each new `Rc` against its client (`src/leaks.rs:3-7`). Without `rc_tracking` the tracker is a zero-sized phantom (`src/leaks.rs:9-39`). With `rc_tracking` it assigns tracker IDs, installs a tracing global allocator, records allocation backtraces, and on demand groups unreleased objects by client with containing allocation and stack evidence (`src/leaks.rs:59-178`, `src/leaks.rs:193-240`, `src/leaks.rs:268-299`). This is a debug facility, not a production GC. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 249 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 250 | ### 3.6 Acceptors |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 251 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 252 | The primary acceptor creates two Unix stream sockets, insecure `wayland-N` and secure `wayland-N.wry`, plus a lock file, scanning `1..1000` (`src/acceptor.rs:66-132`). It unlinks stale paths, takes a nonblocking `flock`, binds, listens with backlog 4096 and stores the lock fd (`src/acceptor.rs:81-142`). It then spawns separate secure and insecure accept loops (`src/acceptor.rs:144-156`). Each accepted fd becomes a `Client` (`src/acceptor.rs:168-191`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 253 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 254 | Tagged acceptors create extra named sockets on demand for a string tag, starting at `wayland-1000` and skipping locked names (`src/tagged_acceptor.rs:63-101`, `src/tagged_acceptor.rs:156-197`). Their metadata carries the tag and non-sandboxed status (`src/tagged_acceptor.rs:72-79`). Their accept loop is otherwise the same (`src/tagged_acceptor.rs:115-135`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 255 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 256 | Security context acceptors do not bind. They accept from a client-supplied listen fd and watch a close fd (`src/security_context_acceptor.rs:22-31`, `src/security_context_acceptor.rs:112-137`). New clients are marked sandboxed with caller-supplied sandbox engine, app id, instance id and bounding caps (`src/security_context_acceptor.rs:59-80`, `src/security_context_acceptor.rs:122-129`). Dual secure plus insecure sockets for one compositor is jay/wry specific. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 257 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 258 | ### 3.7 `wl_usr` |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 259 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 260 | `wl_usr` is a Wayland client stack used by the compositor itself. `UsrCon::new` connects over a Unix socket with io_uring (`src/wl_usr.rs:99-129`). `from_socket` reserves IDs 0 and 1, installs `UsrWlDisplay` object 1, and spawns incoming plus outgoing tasks (`src/wl_usr.rs:131-187`). Outgoing requests reuse the same swapchain and formatter design as server-to-client events (`src/wl_usr.rs:260-279`, `src/wl_usr.rs:281-316`). Incoming events dispatch by object id to `handle_event`, ignoring unknown server IDs but erroring on unknown client IDs (`src/wl_usr.rs:339-357`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 261 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 262 | Client-side objects live in `src/wl_usr/usr_ifs/`. For example `UsrWlCompositor::create_surface` sends the request and tracks the new object (`src/wl_usr/usr_ifs/usr_wl_compositor.rs:17-30`). The generated client trait uses `UsrObject`, `UsrCon` and `UsrConError` (`build/wire.rs:339-347`). The portal uses this to connect to nested displays named `wayland-*.wry` (`src/portal/ptl_display.rs:298-343`), then binds compositor, fractional scale, viewporter, dmabuf and other globals (`src/portal/ptl_display.rs:346-373`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 263 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 264 | ### 3.8 Performance notes |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 265 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 266 | - Fixed messages avoid per-field calls and copy words directly. Variable strings, byte strings and arrays borrow from the input buffer. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 267 | - Small inline storage appears widely, including `SmallVec` for rects, syncs, copies and seats and `ArrayVec` for descriptor layouts, barriers and singleton broadcasts (`src/rect.rs:33`, `src/video/dmabuf.rs:327`, `src/ifs/wl_surface/commit_timeline.rs:553-561`, `src/globals.rs:410`, `src/utils/buffd/buf_in.rs:73`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 268 | - Object maps use custom `CopyHashMap` over hashbrown with unsafe interior access (`src/utils/copyhashmap.rs:21-80`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 269 | - Output buffers and `Buf` storage are recycled rather than reallocated in the swapchain and sender paths. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 270 | - Slow-client detection avoids blocking the compositor on a non-draining peer. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 271 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 272 | ## 4. Vulkan renderer |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 273 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 274 | The reader returned this one as a single dense block with fewer line citations. It is restructured here. Claims marked (verified) were spot-checked by hand. The "bridge" description was corrected, since the code gates it on `for_rendering` (`src/gfx_apis/vulkan/image.rs:535`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 275 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 276 | ### 4.1 Abstraction |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 277 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 278 | The compositor is renderer-agnostic. `GfxApiOp` (`src/gfx_api.rs:115`) has `FillRect` (`:117`), `CopyTexture` (`:118`), `RoundedFillRect` (`:119`) and `RoundedCopyTexture` (`:120`). The `FillRect` struct (`src/gfx_api.rs:286`) and `CopyTexture` (`src/gfx_api.rs:304`) carry `acquire_sync` (`:309`) plus `release_sync` and `lazy` (`:318`). The rounded variants (`:323`, `:344`) mirror that shape. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 279 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 280 | - `LazyTexture` (`src/gfx_api.rs:373`) lets a backend defer work, with `perform_lazy_work` feeding a `Vec<FdSync>`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 281 | - `AcquireSync` (`src/gfx_api.rs:426`) has `None`, `Implicit`, `FdSync` and `Unnecessary`, with `from_fd_sync` (`:434`). `ReleaseSync` (`src/gfx_api.rs:452`) is the release side. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 282 | - `GfxFramebuffer` (`src/gfx_api.rs:503`) exposes `render_with_region_impl` (`:506`) and wrappers through `:889`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 283 | - `GfxTexture` (`src/gfx_api.rs:931`) and `GfxContext` (`src/gfx_api.rs:1030`) complete the surface, with `supports_color_management` (`:1108`) and `supports_alpha_modes` (`:1112`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 284 | - Direct scanout filtering lives near `src/gfx_api.rs:1529`, rejecting `FillRect` (`:1536`) and `RoundedCopyTexture` (`:1540`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 285 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 286 | A second backend exists. `create_gfx_context` (`src/gfx_apis.rs:17`) tries APIs (`:26`) as OpenGL then Vulkan, looping software false then true (`:29`), with dispatch at `:70`. The GL backend (`src/gfx_apis/gl.rs` plus `src/gfx_apis/gl/`, about 3.3k lines) is a full parallel renderer using EGL images, GL textures, and its own `TexCopyType` and `TexSourceType`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 287 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 288 | ### 4.2 Frame recording |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 289 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 290 | A frame is an op list turned into one Vulkan submit. `RendererBase` in compositor code emits `FillRect` and `CopyTexture` ops, and `VulkanRenderer` executes them. `convert_ops` (`src/gfx_apis/vulkan/renderer.rs:1007`, verified) sorts by color, z order and index (`:1030`), then groups by pipeline key. `TexPipelineKey` (`src/gfx_apis/vulkan/renderer.rs:416`, verified) includes copy type, source type, alpha mode, EOTF pair, color matrix presence, grayscale and rounded. A separate `OutPipelineKey` (`:434`) covers the resolve pass. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 291 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 292 | Recording centers on `record_draws` (`src/gfx_apis/vulkan/renderer.rs:1729`), `begin_rendering` (`:1620`), `submit` (`:2393`) and `execute` (`:2475`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 293 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 294 | - `begin_rendering` uses Vulkan 1.3 dynamic rendering with `cmd_begin_rendering` (`:1685`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 295 | - Full-area clears use load op `CLEAR` (`:1667`), otherwise partial clears go through `cmd_clear_attachments` (`:1694`). The blend buffer pass uses `DONT_CARE` (`:1668`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 296 | - Viewport and scissor cover the full target (`:1702`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 297 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 298 | Vertex data uses device-addressable buffers. `tex.common.glsl` (`src/gfx_apis/vulkan/shaders/tex.common.glsl:8`) declares a `buffer_reference` `Vertices` with push-constant `Data` carrying vertices and `mul` (`:12`). This avoids vertex bindings and lets one instanced draw consume many rects from a data buffer. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 299 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 300 | Specialization uses seven constants in `frag_spec_const.glsl` (`src/gfx_apis/vulkan/shaders/frag_spec_const.glsl:4`): `src_has_alpha`, `has_alpha_multiplier`, `eotf`, `inv_eotf`, `has_matrix`, `alpha_mode` and `grayscale`. Pipeline creation consumes those as specialization constants. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 301 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 302 | Descriptors have three tiers. Device probing (`src/gfx_apis/vulkan/device.rs:433`) prefers `descriptor_heap` plus `maintenance5`, falls back to `descriptor_buffer` (`:441`), and finally legacy `push_descriptor`. Enablement (`:481`) adds heap and maintenance5 or buffer names. Features (`:490`) enable timeline semaphores, `synchronization2`, `dynamic_rendering` (`:492`), `buffer_device_address` (`:500`), plus heap or buffer features (`:538`). Color bindings are fixed in `tex_set.glsl` (`src/gfx_apis/vulkan/shaders/tex_set.glsl:4`) with `texture2D tex` plus `ColorManagementData` matrix, `EotfArgs` and `InvEotfArgs`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 303 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 304 | Wait setup (`src/gfx_apis/vulkan/renderer.rs:2254`) imports dmabuf sync files and explicit `FdSync` into `TOP_OF_PIPE` waits. Submit uses `queue_submit2` (`:2409`) and stores `release_sync` (`:2417`). Pending frames (`:2439`) retain command buffers, images, semaphores and heap entries and spawn `await_release` on the async engine (`:2463`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 305 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 306 | ### 4.3 Upload and import |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 307 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 308 | - SHM textures are created `OPTIMAL`, `SAMPLED` plus `TRANSFER_DST`, and filled from staging buffers with `BufferImageCopy2` limited to damage. `transfer.rs` computes copies with queue-family ownership barriers and granularity masks and expands for 4-byte alignment. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 309 | - The async path uses `CpuWorker` jobs `IoTransferJob` and `CopyTransferJob` (`src/gfx_apis/vulkan/transfer.rs:633`, `:642`, verified) with ring readable waits for gfx queue release. The sync path submits a buffer-image copy on the gfx queue directly. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 310 | - Dmabuf import in `image.rs` uses explicit DRM format modifier creation with per-plane fd import and `bind_image_memory2`, and checks disjoint planes and single-file reuse. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 311 | - When a dmabuf's modifier is not renderable, rendering goes into an intermediate "bridge" image and is copied out (`src/gfx_apis/vulkan/image.rs:97`, `:113`, `:535`, verified). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 312 | - Shm reuse checks dimensions and format before reallocating. Internal framebuffers, read-write images and blend buffers are cached by size. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 313 | - The blend buffer is `ABGR16161616F` (`src/gfx_apis/vulkan/format.rs:100`, verified). It holds linear working space, then an out pass resolves to the framebuffer. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 314 | - Staging shells and dmabuf host buffers reduce mapping churn. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 315 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 316 | ### 4.4 Synchronization |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 317 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 318 | `FdSync` (`src/gfx_api.rs:1384`) is `SyncFile` or `Syncobj`, with async wait (`:1392`), blocking wait (`:1408`), poll (`:1434`) and external ring integration (`:1474`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 319 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 320 | - The acquire path (`src/gfx_apis/vulkan/renderer.rs:2254`) dups explicit sync files (`:2303`) and exports dmabuf sync files with `DMA_BUF_SYNC_READ` for textures (`:2313`) and `DMA_BUF_SYNC_WRITE` for the framebuffer (`:2322`), plus an extra `FdSync` list (`:2329`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 321 | - The release path (`:2343`) attaches the submit fence or timeline point to buffer reservations (`:2357`) or imports into dmabufs (`:2361`), with a fallback warning relying on implicit sync. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 322 | - Async SHM tracking sets `last_gfx_use` (`:2381`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 323 | - Device sync creation (`:2401`) returns a fence or timeline semaphore, and submit signals it. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 324 | - Timeline opaque fd export is probed (`src/gfx_apis/vulkan/device.rs:472`) and mapped to DRM syncobj points with a two-point validation handshake in `timeline_semaphore.rs`. Binary semaphores import `SYNC_FD` in `semaphore.rs`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 325 | - Pending frame release uses the async engine and io_uring readable waits. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 326 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 327 | ### 4.5 Memory |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 328 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 329 | Memory uses gpu-alloc, not a custom allocator and not VMA. `Cargo.toml:55` pins `ash` as `jay-ash` 0.12.0, `:56` `gpu-alloc` 0.6.0 and `:57` `gpu-alloc-types` 0.3.0 (verified). `allocator.rs` wraps `AshMemoryDevice` in `VulkanAllocator` and `VulkanThreadedAllocator` with CpuWorker async alloc and free, and zeroed pages via `Config::i_am_prototyping`. Separate small caches exist for shader buffers, uniform buffers and descriptor buffers, plus size-keyed blend buffer and image caches. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 330 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 331 | ### 4.6 Color management and HDR |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 332 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 333 | Color work happens in shaders, driven by CPU-side color descriptions. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 334 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 335 | `tex.frag` steps in order. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 336 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 337 | 1. Sample with `textureLod` (`src/gfx_apis/vulkan/shaders/tex.frag:18`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 338 | 2. Unpremultiply electrical-premultiplied inputs (`:21`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 339 | 3. Apply EOTF (`:24`) and handle optical unpremultiply. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 340 | 4. Apply matrix (`:29`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 341 | 5. Optional grayscale with Rec 709 luma (`:31`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 342 | 6. Inverse EOTF (`:35`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 343 | 7. Repremultiply (`:37`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 344 | 8. Alpha multiplier (`:41`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 345 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 346 | `out.frag` (`src/gfx_apis/vulkan/shaders/out.frag:16`) fetches from the blend buffer and repeats EOTF, matrix and inverse EOTF (`:17`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 347 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 348 | `eotfs.glsl` defines `TF_LINEAR` through `TF_COMPOUND_POWER_2_4` (`src/gfx_apis/vulkan/shaders/eotfs.glsl:7`), with PQ (`:38`), BT1886 with four args (`:20`), ST240, log, ST428, pow and compound variants, dispatched by `apply_eotf` (`:121`) and `apply_inv_eotf` (`:139`). Alpha modes (`src/gfx_apis/vulkan/shaders/alpha_modes.glsl:4`) are premultiplied electrical, premultiplied optical and straight. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 349 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 350 | ### 4.7 copy_device.rs |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 351 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 352 | A separate minimal Vulkan copy engine for multi-GPU movement, used by neither screencast nor the main compositor render path. `PhysicalCopyDevice` and `CopyDevice` classify `TransferType` and direction as Blit, Intra, Download or Upload. Entry points are `create_buffer` (`src/copy_device.rs:1037`, `:1342`), `create_fixed_copy` (`:1233`) and `create_copy` (`:1242`). `State` holds `render_ctx_prime_copy_device` (`src/state.rs:277`), assigned from the DRM device (`src/state.rs:2803`). Metal allocator call sites copy render to device BOs (`src/backends/metal/allocator.rs:1149`, `:1212`, `:1235`, `:1395`), including udmabuf staging (`:1507`). Prime modifier feedback reads `render_ctx_prime_modifiers` (`src/dmabuf_feedback.rs:141`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 353 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 354 | ### 4.8 Decorations |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 355 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 356 | Effects stop at rounded rectangles and borders. The rounding SDF (`src/gfx_apis/vulkan/shaders/rounding.glsl:1`) returns zero outside bounds, selects corner radius and center per quadrant, and smoothsteps distance with half-pixel width (`:24`). Shader families include `fill`, `rounded_fill`, `tex` and `rounded_tex`, plus legacy variants under `src/gfx_apis/vulkan/shaders/legacy`. No blur and no shadow passes exist. `RendererBase` emits tab bars, borders and highlights as `FillRect` and `RoundedFillRect` ops. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 357 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 358 | ### 4.9 Coupling and requirements |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 359 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 360 | Coupling is broad outside the Vulkan directory. `vulkan.rs`, `renderer.rs`, `image.rs`, `device.rs`, `transfer.rs`, `shm_image.rs` and `pipeline.rs` import crate `backend`, `cmm`, `gfx_api`, `theme`, `utils`, `video`, `allocator`, `state`, async engine, ring and CPU worker types. The GL context (`src/gfx_apis/gl.rs:21`) shows the same pattern. A port would carry color management, dmabuf, syncobj, timeline and worker abstractions or stub them. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 361 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 362 | - Vulkan 1.3. `VULKAN_API_VERSION` (`src/vulkan_core.rs:356`) equals `API_VERSION_1_3` (`:15`). The loader uses `libvulkan.so.1` (`:67`, `:73`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 363 | - Required instance extensions (`src/vulkan_core.rs:268`) are `debug_utils` only. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 364 | - Required device extensions (`src/gfx_apis/vulkan/device.rs:728`) include `external_memory_fd`, `external_semaphore_fd`, `external_fence_fd`, `external_memory_dma_buf`, `queue_family_foreign`, `image_drm_format_modifier` and `push_descriptor`. Optional paths add `descriptor_heap` plus `maintenance5`, or `descriptor_buffer`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 365 | - Shaders compile offline. `compile` (`compile-shaders/compile/src/main.rs:18`) maps frag and vert to shaderc kinds (`:33`) and writes SPIR-V (`:44`), with an include callback (`:27`) and hash tracking via `TREES` (`:9`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 366 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 367 | ### 4.10 Unusual choices |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 368 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 369 | - Linear fp16 blend buffer with a separate resolve pass. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 370 | - Device-address vertex buffers fed through push constants. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 371 | - Specialization-constant-driven color pipelines. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 372 | - Damage-limited staging copies, optionally on the cpu_worker thread. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 373 | - Threaded gpu-alloc. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 374 | - Vulkan timeline semaphore to DRM syncobj point mapping. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 375 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 376 | ## 5. Tree, transactions, multiphase animations (jay-port branch, NOT the reference, see round2-reports.md section 6) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 377 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 378 | ### 5.1 Commit timeline |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 379 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 380 | Each client owns `CommitTimelines` (`src/client.rs:229`) and each `WlSurface` owns a `CommitTimeline` (`src/ifs/wl_surface.rs:778`). Shared state is in `src/ifs/wl_surface/commit_timeline.rs:62-70`, with per-surface `own_timeline`, `effective_timeline` plus waiters for fifo, commit time, restore, serial and unmap (`src/ifs/wl_surface/commit_timeline.rs:77-87`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 381 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 382 | `wl_surface.commit` validates release protocols then hands `PendingState` to the timeline (`src/ifs/wl_surface.rs:1286-1316`). Sync subsurface commits do not reach the timeline. They merge into the parent pending and abort (`src/ifs/wl_surface/wl_subsurface.rs:414-427`). Sync state is `sync_requested or sync_ancestor` (`src/ifs/wl_surface/wl_subsurface.rs:255-256`). Desync flushes cached child state through the timeline (`src/ifs/wl_surface/wl_subsurface.rs:287-293`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 383 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 384 | Immediate apply happens only with no dependencies, an empty queue and no fifo barrier (`src/ifs/wl_surface/commit_timeline.rs:275-282`). Otherwise an `EntryKind::Commit` is queued. Client depth is capped at 256 with a `Depth` error (`src/ifs/wl_surface/commit_timeline.rs:58-60`, `src/ifs/wl_surface/commit_timeline.rs:283-285`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 385 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 386 | The collector gathers acquire points, shm uploads, dmabuf presence, prime need, acquire files, commit time and restore flags (`src/ifs/wl_surface/commit_timeline.rs:243-263`, `src/ifs/wl_surface/commit_timeline.rs:963-1005`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 387 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 388 | - Explicit acquire points come from `set_acquire_point` (`src/ifs/wl_surface/wp_linux_drm_syncobj_surface_v1.rs:59-63`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 389 | - Implicit dmabuf fences are added as plane fds when neither syncobj sync nor sync-file acquire is present (`src/ifs/wl_surface/commit_timeline.rs:977-984`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 390 | - Sync-file acquire is added in `src/ifs/wl_surface/commit_timeline.rs:986-988`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 391 | - Fifo flags come from `set_barrier` and `wait_barrier` (`src/ifs/wl_surface/wp_fifo_v1.rs:43-50`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 392 | - Commit time comes from `set_timestamp` (`src/ifs/wl_surface/wp_commit_timer_v1.rs:45-61`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 393 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 394 | Waits are registered without blocking the main thread. Syncobj uses `wfs.wait` (`src/ifs/wl_surface/commit_timeline.rs:321-331`). Implicit fds use `ring.readable_external` (`src/ifs/wl_surface/commit_timeline.rs:340-350`). Shm uploads, prime copies, commit time, restore, serial and unmap mark `needs_flush` (`src/ifs/wl_surface/commit_timeline.rs:333-364`). The queue head is flushed when previously empty (`src/ifs/wl_surface/commit_timeline.rs:366-368`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 395 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 396 | Queues are FIFO (`src/ifs/wl_surface/commit_timeline.rs:569-579`). The head applies only when all dependencies clear (`src/ifs/wl_surface/commit_timeline.rs:582-653`). Other clients have separate `Inner` queues, so one blocked surface does not stop another client except through explicit cross-timeline links. Parent and subsurface timelines are unified through `set_effective_timeline` (`src/ifs/wl_surface/commit_timeline.rs:1008-1034`) using `Wait` and `Signal` entries (`src/ifs/wl_surface/commit_timeline.rs:529-534`). Later wakeups go through per-client `process_flush_requests` (`src/ifs/wl_surface/commit_timeline.rs:1041-1053`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 397 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 398 | Completion callbacks decrement counters and retry the list. This covers syncobj (`src/ifs/wl_surface/commit_timeline.rs:430-442`), shm upload (`src/ifs/wl_surface/commit_timeline.rs:453-468`), prime copy (`src/ifs/wl_surface/commit_timeline.rs:470-485`), dmabuf poll (`src/ifs/wl_surface/commit_timeline.rs:487-501`) and commit timer timeout (`src/ifs/wl_surface/commit_timeline.rs:504-521`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 399 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 400 | Fifo barrier handling parks `Queued` commits as `Registered` and stores `fifo_waiter` (`src/ifs/wl_surface/commit_timeline.rs:600-612`). Barrier release pushes the waiter (`src/ifs/wl_surface/commit_timeline.rs:376-381`). Latch clears it for normal presentation but defers to vblank under tearing (`src/ifs/wl_surface.rs:2561-2584`), with vblank cleanup in `src/ifs/wl_surface.rs:2543-2552`. Applied commits set the barrier (`src/ifs/wl_surface.rs:1664-1688`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 401 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 402 | Commit timer registration subtracts render plus flip margins from the requested time (`src/ifs/wl_surface/commit_timeline.rs:702-730`). It uses `ring.timeout_external` and attaches a `before_latch_listener`, then `before_latch` releases the commit when presentation time has passed (`src/ifs/wl_surface/commit_timeline.rs:405-427`, `src/ifs/wl_surface.rs:2555-2559`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 403 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 404 | Destroy versus loop breaking is split (`src/ifs/wl_surface/commit_timeline.rs:210-235`), with dependency state discarded in `src/ifs/wl_surface/commit_timeline.rs:197-208` and destroyed timelines drained through a `Gc` entry (`src/ifs/wl_surface/commit_timeline.rs:660-663`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 405 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 406 | ### 5.2 Layout transactions |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 407 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 408 | Tree mutation uses `Transactionable` and `TransactionData` (`src/transactions.rs:20-38`, `src/transactions.rs:65-71`). Any op schedules the object and triggers serial groups (`src/transactions.rs:195-209`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 409 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 410 | `Transactions::commit` snapshots scheduled objects, surfaces and effects, creates or recycles a `Transaction` plus `Blocker`, queues surface blockers and assigns member ops (`src/transactions.rs:216-282`). Surfaces receive `UnblockCommitsUntil` (`src/transactions.rs:230-237`). Apply runs `before_apply`, member ops, `after_apply`, then recycles the transaction (`src/transactions.rs:284-299`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 411 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 412 | `Blocker` drop schedules apply exactly once by version (`src/transactions.rs:345-359`). Timeout applies the same version after a 50ms default (`src/transactions.rs:78-80`, `src/transactions.rs:441-467`). The apply loop is separate (`src/transactions.rs:469-475`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 413 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 414 | Per-surface blocking is in `src/transactions.rs:116-127`. `unblock_transactions_until` drops blockers at or before the committed serial (`src/transactions.rs:374-400`). `commit_is_blocked` compares `unblocked_commit` against the needed serial (`src/transactions.rs:417-419`). Disabled means tardy or zero enable count (`src/transactions.rs:421-423`). Missing acks mark `tardy`, clear blockers and force the timeout path (`src/transactions.rs:402-415`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 415 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 416 | The commit timeline and layout transaction meet in `maybe_apply` (`src/ifs/wl_surface/commit_timeline.rs:632-638`). The surface first records the serial, then parks on `serial_waiter` if still blocked. Publication calls `serial_unblocked` through `WlSurfaceTransactionOp::UnblockCommitsUntil` (`src/ifs/wl_surface.rs:2696-2702`), with waiter release in `src/ifs/wl_surface/commit_timeline.rs:393-397`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 417 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 418 | Each serial group tick allocates one `TreeSerial`, commits transactions, then runs configure groups (`src/tree_serial_groups.rs:18-30`). Configures are grouped by serial (`src/configurable.rs:241-280`). `schedule_configure` also adds the surface to transactions (`src/configurable.rs:91-105`). Readiness counting releases whole groups (`src/configurable.rs:170-189`, `src/configurable.rs:336-410`). Flush sends the serial and records `requested_serial` (`src/configurable.rs:218-239`). The client ack must carry at least that serial before `ready` (`src/ifs/wl_surface.rs:1307-1312`, `src/ifs/wl_surface.rs:1370-1374`). The t0061 test asserts `LiveTL` moves first while `RenderTL` stays old until commit (`src/it/tests/t0061_transactional_layout_animation.rs:35-47`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 419 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 420 | ### 5.3 Tree |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 421 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 422 | Node behavior is `NodeBase` (`src/tree.rs:445-945`) with dyn wrapper `Node` (`src/tree.rs:947-968`). Visitors are in `src/tree/walker.rs:18-86`. Timelines are `LiveTL` and `RenderTL` (`src/tree.rs:976-981`), with `SplitView` maps (`src/tree.rs:984`). Links carry per-timeline validity (`src/tree.rs:985-1008`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 423 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 424 | Layers are ordered `Display` through `OverlayStacked` (`src/tree.rs:343-365`), with linked variants in `src/tree.rs:367-385`. Concrete types include `DisplayNode` (`src/tree/display.rs:47`), `OutputNode` (`src/tree/output.rs:131`), `WorkspaceNode` (`src/tree/workspace.rs:76-98`), containers, floats, toplevels and placeholders. Parents implement `ContainingNode` (`src/tree/containing.rs:7-59`). Toplevel behavior splits into `ToplevelNodeBase` (`src/tree/toplevel.rs:366`) and `ToplevelNode` (`src/tree/toplevel.rs:81-101`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 425 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 426 | Rendering walks the same hierarchy through `node_render` and `node_visit_children`. Examples are output (`src/tree/output.rs:2477`), container (`src/tree/container.rs:2953`), workspace (`src/tree/workspace.rs:559`), float (`src/tree/float.rs:972`), display (`src/tree/display.rs:285`) and placeholder (`src/tree/placeholder.rs:229`). The renderer starts from outputs and workspaces, then stacked layers and exit frames (`src/renderer.rs:250-303`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 427 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 428 | ### 5.4 Multiphase animations |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 429 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 430 | A phase is a `MultiphasePhase` with one action plus steps (`src/presentation/multiphase.rs:204-209`). Each step is classified as horizontal or vertical move or scale (`src/presentation/multiphase.rs:1486-1509`). Diagonal or size-plus-position changes cannot be one phase and force multiphase plans. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 431 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 432 | The planning entry is `plan_no_overlap` (`src/presentation/multiphase.rs:354-356`), with forward then reversed attempts (`src/presentation/multiphase.rs:364-412`). Strategies include `SingleAction`, `SpaceThenOrthogonalGrowth`, `HierarchyOrderedScales`, `OrientationChange`, `SwapLanes` and reversed plans (`src/presentation/multiphase.rs:159-168`), tried in that order (`src/presentation/multiphase.rs:535-616`). Independent motion groups split first (`src/presentation/multiphase.rs:460-488`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 433 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 434 | Validation checks chaining, duplicates, action counts, unknown nodes, stale starts, intra-phase overlap and final rects (`src/presentation/multiphase.rs:1280-1368`). Overlap uses linear edge deltas with rational time intervals (`src/presentation/multiphase.rs:1370-1484`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 435 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 436 | Runtime animations store multiple `from to` segments (`src/presentation/layout_animation.rs:160-168`). Total time is duration times phase count (`src/presentation/layout_animation.rs:1292-1296`). Position interpolates within the current phase with the configured curve (`src/presentation/layout_animation.rs:1309-1319`). Interrupts retarget from the current `rect_at` (`src/presentation/layout_animation.rs:846-892`, `src/presentation/layout_animation.rs:894-952`, `src/presentation/layout_animation.rs:1112-1129`). Path validation for reversed interrupts is in `src/presentation/multiphase.rs:414-458`. Appearing windows can wait behind existing phases (`src/presentation/layout_animation.rs:976-1018`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 437 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 438 | Ticks are per-output `LatchListener`s (`src/presentation/layout_animation.rs:257-260`, `src/presentation/layout_animation.rs:1945-1960`). Each latch damages active rects and stops when idle (`src/presentation/layout_animation.rs:1218-1248`). Ticks attach to `output.latch_event` (`src/presentation/layout_animation.rs:1250-1269`) and detach in `src/presentation/layout_animation.rs:1271-1289`. The test asserts latch drives damage and that output disconnect or reconnect changes tick count (`src/it/tests/t0061_transactional_layout_animation.rs:69-90`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 439 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 440 | Animations are transaction effects. The trait observes pre and post trees without mutating live state (`src/transactions.rs:45-58`). Scheduling adds effects (`src/presentation/layout_animation.rs:561-738`). Single moves capture the before rect plus current visual (`src/presentation/layout_animation.rs:1472-1514`). Batches capture whole container snapshots before and after (`src/presentation/layout_animation.rs:1596-1664`), with coalescing per container (`src/presentation/layout_animation.rs:1666-1671`). Direct manipulation first cancels animations then suppresses new ones for that transaction (`src/presentation/layout_animation.rs:527-559`, `src/presentation/layout_animation.rs:1516-1522`). The test asserts no animation before publication and a multiphase spawn after (`src/it/tests/t0061_transactional_layout_animation.rs:92-127`), plus no animation for direct manipulation (`src/it/tests/t0061_transactional_layout_animation.rs:129-146`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 441 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 442 | Old pixels use retained captures. `RetainedToplevel`, `RetainedSurface` and `RetainedContent` hold textures or colors plus subsurface offsets (`src/presentation/layout_animation.rs:107-153`). Capture clones live buffers and subsurface structure (`src/presentation/layout_animation.rs:1355-1469`). Exits expose timed frames (`src/presentation/layout_animation.rs:766-778`). Spawns expose retained frames while resizing (`src/presentation/layout_animation.rs:780-794`). Close while blocked produces no exit until timeout publication (`src/it/tests/t0061_transactional_layout_animation.rs:151-174`). Closing mid-animation hands the presented rect to the exit (`src/it/tests/t0061_transactional_layout_animation.rs:176-201`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 443 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 444 | ### 5.5 layout_animation computation and render plug-in |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 445 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 446 | It computes curve samples, spawn endpoints, roll edges, batch plans, per-node visual rects, damage and retained frames. Curves include linear and flattened cubic bezier (`src/presentation/layout_animation.rs:281-323`, `src/presentation/layout_animation.rs:326-411`). Spawn endpoints cover grow, fly and roll (`src/presentation/layout_animation.rs:413-450`), with edge helpers in `src/presentation/layout_animation.rs:452-519`. Batch planning filters to moving windows, partitions groups, then plans or falls back to direct interpolation (`src/presentation/layout_animation.rs:954-1110`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 447 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 448 | Render integration reads `visual_rect` for fullscreen, container children and mono bodies (`src/renderer.rs:311-330`, `src/renderer.rs:470-505`, `src/renderer.rs:571-589`). Exit frames render above tiled or floating stacks (`src/renderer.rs:256-274`, `src/renderer.rs:737-765`). Spawns render retained content scaled from source to target size (`src/renderer.rs:767-820`, `src/renderer.rs:822-860`). Client damage follows the presented window through `visual_damage` (`src/ifs/wl_surface.rs:1735-1752`, `src/presentation/layout_animation.rs:747-764`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 449 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 450 | ### 5.6 Tree verify |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 451 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 452 | `verify_tree_invariants` checks both timelines (`src/tree/verify.rs:14-22`) and runs after idle in integration tests (`src/it/testrun.rs:198-201`). It checks output identity and dummy status, active workspace membership, workspace-to-output links, toplevel parent and workspace pointers, float workspace and display stack membership, fullscreen uniqueness and placeholder linkage, scratchpad mapping and container snapshots (`src/tree/verify.rs:72-108` and following). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 453 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 454 | Container checks include nonempty children, cached counts, child map identity, finite nonnegative factors, factor sum tolerance, focus history and backlinks, mono child placement, no pending layout and non-mono overlap (`src/tree/verify.rs:671-853`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 455 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 456 | ### 5.7 Unusual choices |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 457 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 458 | - Per-client commit queues plus per-surface timelines with explicit cross-timeline signals. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 459 | - Shm upload, prime copy, dmabuf poll, fifo, commit time, restore, serial and unmap are treated uniformly as queue blockers. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 460 | - The tardy path that discards blockers and relies on timeout is pragmatic. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 461 | - A collision-free geometric planner with exact rational overlap checks drives window animation. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 462 | - Retained textures render scaled from old source size to animated target size while clients resize. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 463 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 464 | ## 6. Process model, config, tests, utilities |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 465 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 466 | ### 6.1 Startup |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 467 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 468 | - `main()` only calls `cli::main()` (`src/main.rs:138-140`). CLI parsing decides run vs control commands (`src/cli.rs:312-356`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 469 | - Non-`run` commands drop all process capabilities immediately (`src/cli.rs:320-322`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 470 | - `Cmd::Run` calls `start_compositor` (`src/cli.rs:327`). It resets signal handlers (`src/compositor.rs:162-164`), makes the process a child subreaper or re-execs under one (`src/compositor.rs:164`, `src/utils/clone3.rs:87-115`), snapshots capabilities (`src/compositor.rs:165`), and keeps only `CAP_SYS_NICE` for the compositor (`src/pr_caps.rs:83-115`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 471 | - If `CAP_SYS_NICE` survived, it elevates the scheduler and moves the privileged capability onto a dedicated helper thread (`src/compositor.rs:166-172`, `src/pr_caps.rs:122-147`). The reaper child also drops caps (`src/utils/clone3.rs:116`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 472 | - The forker is created next (`src/compositor.rs:173-174`), before logging, io_uring, threads, portal, or graphics. Later startup creates threads and io_uring state that must not be forked. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 473 | - Startup then spawns the portal helper, sleeper, profiler, and logger (`src/compositor.rs:174-184`), then builds the full `State` in `start_compositor2` (`src/compositor.rs:253-536`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 474 | - `start_compositor2` installs the Wayland acceptor, IPC acceptor, forker environment, portal task, and compositor task, then runs io_uring (`src/compositor.rs:495-535`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 475 | - The forker child sanitizes its environment by forcing `XDG_SESSION_TYPE=wayland` and removing `DISPLAY`/`WAYLAND_DISPLAY` (`src/forker.rs:343-348`), renames itself (`src/forker.rs:349`), takes `SIGKILL` on parent death (`src/forker.rs:350`, `src/forker.rs:584-592`), ignores `SIGCHLD` (`src/forker.rs:351-353`), and collapses its fds so only the control socket survives (`src/forker.rs:569-582`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 476 | - `start_compositor3` selects a backend, publishes sockets, loads config, creates the default seat, starts global handlers and Xwayland, then runs the backend (`src/compositor.rs:538-588`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 477 | - Backend order defaults to X11 then Metal (`src/compositor.rs:755-758`). Config is loaded after graphics/backend selection but before seats and Xwayland (`src/compositor.rs:565-581`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 478 | - `RLIMIT_NOFILE` is raised to the hard limit by default (`src/compositor.rs:797-814`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 479 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 480 | ### 6.2 Forker |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 481 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 482 | - `ForkerProxy::create` makes a control socketpair and calls `double_fork` (`src/forker.rs:99-119`). The parent gets a pidfd and the child enters `Forker::handle` (`src/forker.rs:114-118`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 483 | - `double_fork` uses pidfd-carrying socketpairs so both stages reliably learn child pidfds (`src/utils/clone3.rs:24-48`, `src/utils/clone3.rs:50-85`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 484 | - The compositor never calls `fork`/`exec` directly for clients. It queues `ServerMessage::Spawn` plus separately passed fds (`src/forker.rs:206-225`, `src/forker.rs:276-290`). The forker re-forks, remaps fds with collision handling, applies env deltas, and execs (`src/forker.rs:449-546`, `src/forker.rs:594-616`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 485 | - It is forked early because only an early, single-threaded, pre-graphics process can safely `fork` again later. It also owns the child environment via `SetEnv` (`src/forker.rs:139-151`, `src/forker.rs:423-431`) and reports exec failures and pidfds back (`src/forker.rs:473-503`, `src/forker.rs:548-556`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 486 | - Xwayland is one special spawn with fixed fds stderr=2, displayfd=3, listenfd=4, wm=5, wayland=6 (`src/forker.rs:170-194`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 487 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 488 | ### 6.3 Config |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 489 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 490 | - Current config is in-process and typed. `ConfigProxy::default` wires the compositor handler directly to `wry_toml_config::configure` through `wry_config::_private::client::init` (`src/config.rs:255-259`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 491 | - `init` takes a `Weak<dyn ConfigServerEndpoint>`, an `InitMessage`, and a configure function pointer (`wry-config/src/_private/client.rs:242-246`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 492 | - Traffic consists of cloned Rust enums such as `ServerMessage`, `ClientMessage`, and `Response` (`wry-config/src/_private/ipc.rs:84-150`, `src/config/handler.rs:101-117`). `ConfigProxyHandler::send` calls `client.handle(msg.clone())` with no serialization (`src/config/handler.rs:324-328`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 493 | - No `dlopen`/`libloading`/`config.so` loading remains in `src/config/handler.rs`. The public docs still describe a `cdylib` plus `config!` workflow (`wry-config/src/lib.rs:19-33`), but `wry-config/src/macros.rs:1-28` now only defines `try_get!`/`get!`, so that documentation looks stale. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 494 | - The high-level `wry-config` API exposes seats, windows, workspaces, video/connectors, input, keyboard, theme, timers, tasks, exec, logging, and lifecycle calls (`wry-config/src/lib.rs:61-79`, `wry-config/src/lib.rs:107-122`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 495 | - `reload()` calls into the ambient config client (`wry-config/src/lib.rs:117-122`), becomes `ClientMessage::Reload` (`src/config/handler.rs:3714`), invokes `state.reload_config()` (`src/config/handler.rs:523-525`), and reissues `configure(true)` (`src/state.rs:2497-2502`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 496 | - Every configure sends feature negotiation then `Configure { reload }` (`src/config.rs:240-253`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 497 | - The TOML implementation preserves a `PersistentState` across reloads and clears ephemeral actions/rules/triggers/counters on unload (`toml-config/src/lib.rs:2118-2145`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 498 | - Unload clears timers, pollables, and client/window matchers (`src/config/handler.rs:307-322`), while `ConfigProxy::destroy` drops the client endpoint (`src/config.rs:48-52`) and `Clear` is available as an explicit message (`src/config.rs:128-130`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 499 | - There is a versioned `VERSION = 1` and feature list (`wry-config/src/_private.rs:21-29`, `wry-config/src/_private/ipc.rs:69-82`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 500 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 501 | ### 6.4 Xwayland |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 502 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 503 | - Xwayland is started lazily. The manager allocates and listens on an X socket, exports `DISPLAY`, then waits for a readable connection attempt before launching Xwayland (`src/xwayland.rs:106-133`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 504 | - Launch uses fixed args including `-terminate`, `-rootless`, `-displayfd 3`, `-listenfd 4`, `-wm 5`, plus optional `-enable-ei-portal` after probing `Xwayland -help` (`src/xwayland.rs:231-282`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 505 | - The compositor creates a privileged Wayland client for the Xwayland process itself (`src/xwayland.rs:188-203`), waits for the displayfd signal (`src/xwayland.rs:205`), constructs the WM asynchronously (`src/xwayland.rs:214-219`), and supervises its pidfd (`src/xwayland.rs:220-225`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 506 | - Window management lives in `src/xwayland/xwm.rs:1-60` and speaks X11 through the local `xcon` parser/formatter and generated `wire_xcon` bindings (`src/xcon/parser.rs`, `src/xcon/formatter.rs`, `src/xcon/consts.rs`, `src/xwayland/xwm.rs:54-60`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 507 | - Compositor-level Xwayland supervision is one async task installed once (`src/state.rs:1630-1638`), and stopping only clears the task when the server is not running (`src/state.rs:1640-1645`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 508 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 509 | ### 6.5 Integration tests |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 510 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 511 | - Tests are in-process and feature-gated (`src/compositor.rs:205-218`, `src/cli.rs:145-151`, `src/cli.rs:350-351`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 512 | - Each test boots a fresh compositor with `TestBackend` via `start_compositor_for_test` (`src/it.rs:124-186`, `src/compositor.rs:747-754`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 513 | - `TestBackend` provides an 800x600 virtual connector, keyboard, mouse, and test graphics context (`src/it/test_backend.rs:97-120`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 514 | - Virtual clients connect over a real Unix socket to the test acceptor and speak Wayland through `TestTransport` (`src/it/testrun.rs:53-107`, `src/it/test_transport.rs:35-80`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 515 | - Config is replaced by a thread-local `TestConfig` implementing the same typed config endpoint (`src/it/test_config.rs:34-113`, `src/config.rs:261-264`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 516 | - Test mode zeroes configure/transaction timeouts (`src/compositor.rs:575-578`). Each test runs as a `Phase::Present` future with a watchdog timeout (`src/it.rs:156-172`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 517 | - Tests run in parallel across worker threads, one isolated runtime dir per process (`src/it.rs:46-52`, `src/it.rs:77-103`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 518 | - There are about 73 `src/it/tests/t*.rs` cases, plus protocol-object helpers under `src/it/test_ifs/` and utilities under `src/it/test_utils/`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 519 | - Assertions cover tree geometry and focus (`src/it/tests/t0002_window.rs:9-28`), protocol behavior, session-manager state, and golden pixels. The scaled-render test renders through the real screenshot path and byte-compares QOI output (`src/it/tests/t0071_scaled_render.rs:22-60`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 520 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 521 | ### 6.6 `sm` |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 522 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 523 | - `sm` is a SQLite-backed Wayland session manager (`src/sm.rs:1-56`, `src/compositor.rs:287-292`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 524 | - It models sessions, named toplevel sessions, owners, and asynchronous acquire/rename/update/disown jobs (`src/sm.rs:66-144`, `src/sm.rs:209-228`, `src/sm.rs:359-384`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 525 | - Toplevel state tracks output, workspace, floating rectangle, and fullscreen (`src/sm.rs:178-186`, `src/sm.rs:484-539`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 526 | - Persistence work is scheduled as SQLite jobs and flushed by a background task (`src/sm.rs:464-475`, `src/sm.rs:681-705`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 527 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 528 | ### 6.7 Keyboard and input |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 529 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 530 | - `kbvm` is an external crates.io dependency, version 0.1.7 with `compose` (`Cargo.toml:64`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 531 | - It supplies the XKB context, RMLVO/keymap compilation, state machine, and lookup tables (`src/kbvm.rs:42-72`, `src/kbvm.rs:105-164`, `src/kbvm.rs:289-323`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 532 | - Keymaps are sealed memfds, with a separate Xwayland-compatible rendering (`src/kbvm.rs:210-231`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 533 | - `libinput` is used through unsafe FFI, with no evdev reimplementation. The code binds `libinput_path_create_context`, dispatch, event, fd, logging, and ref functions (`src/libinput.rs:15-26`), supplies restricted open/close callbacks (`src/libinput.rs:39-63`), forwards libinput logs (`src/libinput.rs:176-195`), and unrefs on drop (`src/libinput.rs:168-174`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 534 | - Local `evdev` code is only a small `EVIOCGBIT` key-capability helper (`src/evdev.rs:1-34`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 535 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 536 | ### 6.8 Homegrown utilities |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 537 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 538 | - `CloneCell` (`src/utils/clonecell.rs:9-55`). `UnsafeCell` cell for cheaply cloneable `Rc`/handle types in single-threaded code. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 539 | - `CopyHashMap` (`src/utils/copyhashmap.rs:21-56`). Interior-mutable hashbrown map with access counting and lockable hasher behavior. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 540 | - `NumCell` (`src/utils/numcell.rs:9-30`). `Cell` numeric wrapper with fetch-add/sub and bit operations. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 541 | - `AsyncQueue` (`src/utils/queue.rs:16-54`). Single-consumer async FIFO with waker support. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 542 | - `SyncQueue` (`src/utils/syncqueue.rs:10-37`). Non-async interior-mutable deque. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 543 | - `Stack`/`AsyncStack` (`src/utils/stack.rs:15-48`, `src/utils/stack.rs:72-99`). Interior-mutable `Vec` stacks, optionally awaitable for nonemptiness. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 544 | - `SmallMap` (`src/utils/smallmap.rs:11-58`). Small inline map with interior mutability. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 545 | - `LinkedList` (`src/utils/linkedlist.rs:13-60`). Intrusive-style doubly linked list with manual refcounts. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 546 | - `VecSet` (`src/utils/vecset.rs:4-41`). Small vector-backed set used for pressed keys and similar sets. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 547 | - `RefCounted` (`src/utils/refcounted.rs:8-40`). Manual refcount table with version bumping. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 548 | - `AsyncEvent` (`src/utils/asyncevent.rs:11-42`). Counting one-shot async trigger. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 549 | - `rc_eq`/`RcEq` (`src/utils/rc_eq.rs:5-45`). Pointer-identity equality for `Rc`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 550 | - `ErrorFmt` (`src/utils/errorfmt.rs:5-22`). Formats chained `Error::source` output. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 551 | - `oserror` (`src/utils/oserror.rs:9-60`). Raw errno wrapper plus generated constructors/messages. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 552 | - `clone3` helpers (`src/utils/clone3.rs:24-85`). pidfd-aware fork/double-fork, reaper setup, and child supervision. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 553 | - The workspace also contains its own TOML parser, PHF maps, and wire-format codegen crates (`Cargo.toml:16`, `toml-config/src/toml/`, `toml-config/src/phf.rs`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 554 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 555 | ### 6.9 Tracy |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 556 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 557 | - Profiling is behind the `tracy` Cargo feature (`Cargo.toml:105`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 558 | - Without it, zone/frame macros compile to no-ops (`src/tracy.rs:1-16`, `src/tracy/tracy_noop.rs:21-51`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 559 | - With it, zone names are cached in a global map and emitted through `tracy-client-sys` begin/end calls (`src/tracy/tracy_impl.rs:30-80`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 560 | - The profiler is enabled during normal startup (`src/compositor.rs:176`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 561 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 562 | ### 6.10 Unusual choices |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 563 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 564 | - Nearly everything is single-threaded `Rc` plus `UnsafeCell` interior mutability, with threads isolated to CPU work, SQLite, `CAP_SYS_NICE`, and test runners. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 565 | - Spawning is centralized in a pre-thread double-forked helper that passes fds over a socket and remaps colliding targets. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 566 | - Config, tests, and production share the same typed config traits rather than separate serialization boundaries. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 567 | - The repo vendors protocol-adjacent machinery including X11 wire parsing, Wayland buffer handling, TOML parsing, PHF maps, and XML/wire codegen. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 568 | - SQLite is a core runtime dependency for session state, not merely diagnostics. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 569 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 570 | ## 7. Smithay extension points |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 571 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 572 | Paths in this section are relative to shallow clones of smithay (`023b78b`, 2026-10-15) and calloop (0.14.5), prefixed `smithay/` and `calloop/`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 573 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 574 | ### 7.1 Event loop |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 575 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 576 | calloop 0.14.5 uses the `polling` 3.0.0 crate rather than direct epoll calls (`calloop/Cargo.toml:26`). `Poll` holds an `Arc<Poller>` (`calloop/src/sys.rs:174`) built with `Poller::new()` (`calloop/src/sys.rs:207`). Docs describe it as OS-provided polling with epoll on Linux (`calloop/src/lib.rs:99`). No `io_uring` string appears in calloop or smithay. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 577 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 578 | The futures executor is optional behind the `executor` feature (`calloop/Cargo.toml:41`). It is implemented as `Executor<T>` plus `Scheduler<T>` (`calloop/src/sources/futures.rs:45`), built on `async-task` runnables woken through a `PingSource`. The module docs state futures need their own wakeup means and point at `LoopHandle::adapt_io` (`calloop/src/sources/futures.rs:17`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 579 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 580 | smithay does not hard-require calloop for `wayland-server::Display`. Anvil drives clients by wrapping the display in a generic fd source with `Generic::new(display, Interest::READ, Mode::Level)` then calling `dispatch_clients` and `flush_clients` (`smithay/anvil/src/state.rs:682`, `smithay/anvil/src/udev.rs:544`). The listening socket helper is itself an `EventSource` (`smithay/src/wayland/socket.rs:95`), and other helpers merely provide `EventSource` impls. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 581 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 582 | - `DmabufSource` (`smithay/src/backend/allocator/dmabuf.rs:631`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 583 | - `DrmDeviceNotifier` (`smithay/src/backend/drm/device/mod.rs:525`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 584 | - `UdevBackend` (`smithay/src/backend/udev.rs:130`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 585 | - `LibinputInputBackend` (`smithay/src/backend/libinput/mod.rs:707`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 586 | - `X11Backend` (`smithay/src/backend/x11/mod.rs:561`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 587 | - `WinitEventLoop` (`smithay/src/backend/winit/mod.rs:789`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 588 | - `DrmSyncPointSource` (`smithay/src/wayland/drm_syncobj/sync_point.rs:286`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 589 | - `SecurityContextListenerSource` (`smithay/src/wayland/security_context/listener_source.rs:36`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 590 | - `XWayland` (`smithay/src/xwayland/xserver.rs:279`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 591 | - `EiInput` (`smithay/src/backend/libei/mod.rs:163`) |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 592 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 593 | A compositor could poll the display fd from another loop and call `dispatch_clients` plus `flush_clients` itself, at the cost of those ready-made sources and the `LoopHandle` insertion helpers used across backends and xwayland. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 594 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 595 | ### 7.2 Wayland server |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 596 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 597 | smithay uses `wayland-server` 0.31.13 and `wayland-backend` 0.3.15 as optional deps enabled by `wayland_frontend` (`smithay/Cargo.toml:64`, `smithay/Cargo.toml:66`, `smithay/Cargo.toml:115`). The default is the pure Rust backend. The libwayland system backend is only selected by `use_system_lib` through `wayland-backend/server_system` plus `wayland-sys` (`smithay/Cargo.toml:113`). That feature also gates `gbm?/import-wayland` and the `ImportEgl` path. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 598 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 599 | Dispatch uses `wayland-server` `Dispatch` and `GlobalDispatch`, but smithay modules expose the simpler `Dispatch2` and `GlobalDispatch2` (`smithay/src/wayland/dispatch2.rs:6`, `smithay/src/wayland/dispatch2.rs:25`), with a `delegate_dispatch2` macro (`smithay/src/wayland/dispatch2.rs:45`) that blanket-implements the upstream traits. Each protocol module documents `*State` plus `*Handler` plus `delegate_dispatch2`, for example compositor (`smithay/src/wayland/compositor/mod.rs:63`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 600 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 601 | ### 7.3 Renderer abstraction |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 602 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 603 | Core traits live in `smithay/src/backend/renderer/mod.rs`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 604 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 605 | - `Bind` (`:216`) has `bind` and `supported_formats`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 606 | - `Texture` (`:233`) has `size`, `width`, `height` and `format`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 607 | - `Frame` (`:270`) has `context_id`, `clear`, `draw_solid`, `render_texture_at`, `render_texture_from_to`, `transformation`, `output_size`, `wait` and `finish`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 608 | - `Renderer` plus `RendererSuper` (`:385`, `:402`) have `context_id`, `downscale_filter`, `upscale_filter`, `set_debug_flags`, `debug_flags`, `render`, `wait`, `cleanup_texture_cache` and `invalidate_caches`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 609 | - `Offscreen::create_buffer` (`:467`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 610 | - `ImportMem` (`:511`) with `import_memory`, `update_memory` and `mem_formats`. `ImportMemWl` (`:479`) with `import_shm_buffer` and `shm_formats`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 611 | - `ImportDma` (`:643`) with `dmabuf_formats`, `has_dmabuf_format` and `import_dmabuf`. `ImportDmaWl::import_dma_buffer` (`:618`). `ImportAll::import_buffer` (`:677`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 612 | - `ExportMem` (`:747`) with `copy_framebuffer`, `copy_texture`, `can_read_texture` and `map_texture`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 613 | - `Blit::blit` (`:808`) and `BlitFrame` (`:836`) with `blit_to` and `blit_from`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 614 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 615 | There is no Vulkan renderer in tree. `src/backend/vulkan` only has instance and physical device helpers. Its module docs state it does not provide logical devices, rendering or memory allocation (`smithay/src/backend/vulkan/mod.rs:1`). Vulkan allocation is separate in `src/backend/allocator/vulkan`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 616 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 617 | Multigpu is generic over `GraphicsApi` and `ApiDevice` (`smithay/src/backend/renderer/multigpu/mod.rs:728`, `:749`). A device exposes `renderer`, `renderer_mut`, `allocator` returning a `Dmabuf` allocator, `node`, plus cross-device import hints. Target selection needs `Bind<Dmabuf>` (`:328`), cross rendering needs target-side `ImportDma` (`:394`), and `early_import` needs `ImportMemWl` plus `ImportDmaWl` plus `ExportMem` (`:493`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 618 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 619 | `OutputDamageTracker` (`smithay/src/backend/renderer/damage/mod.rs:193`) exposes `new`, `from_output`, `from_mode_source`, `mode`, `render_output`, `render_output_with_states` and `damage_output` (`:250`, `:279`, `:300`, `:317`, `:326`, `:382`, `:435`). Rendering requires `E: RenderElement<R>` and `R: Renderer`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 620 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 621 | `Element` (`smithay/src/backend/renderer/element/mod.rs:518`) requires `id`, `current_commit`, `src`, `geometry` plus defaulted `location`, `transform`, `damage_since`, `opaque_regions`, `alpha`, `kind` and `is_framebuffer_effect`. `RenderElement` (`:572`) requires `draw` and optionally `underlying_storage` plus `capture_framebuffer`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 622 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 623 | ### 7.4 DRM |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 624 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 625 | `DrmCompositor` docs (`smithay/src/backend/drm/compositor/mod.rs:1`) describe walking elements front to back, assigning overlays, then trying the top fitting element for cursor, and compositing the rest on primary with the supplied renderer. Overlays are atomic-only, with legacy limited to primary, plus `UnderlyingStorage` export and atomic test commits. Scanout permission is controlled by `FrameFlags` (`:1021`) with `ALLOW_PRIMARY_PLANE_SCANOUT`, `ALLOW_PRIMARY_PLANE_SCANOUT_ANY`, `ALLOW_OVERLAY_PLANE_SCANOUT`, `ALLOW_CURSOR_PLANE_SCANOUT`, `SKIP_CURSOR_ONLY_UPDATES`, `ALLOW_SCANOUT` and `DEFAULT`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 626 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 627 | Frame scheduling is caller-driven. `render_frame` (`:1686`) needs `R: Renderer + Bind<Dmabuf>` and prepares planes and damage. `queue_frame` (`:2441`) queues and submits when idle. `commit_frame` (`:2487`) commits without vblank generation. `frame_submitted` (`:2618`) retires the pending frame and submits a queued one. Empty frames must be rescheduled by the caller, typically with a retrace timer. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 628 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 629 | VRR exists on surfaces as `vrr_supported`, `vrr_enabled` and `use_vrr` backed by `VRR_ENABLED` (`smithay/src/backend/drm/surface/atomic.rs:558`, `smithay/src/backend/drm/surface/gbm.rs:502`), with `VrrSupport` values including `RequiresModeset`. No tearing or async flip control, no gamma or CTM or color pipeline properties, and no render-as-late-as-possible deadline API were found in `src/backend/drm/compositor`. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 630 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 631 | ### 7.5 Surface commit handling |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 632 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 633 | Commits use double-buffered cached state plus transactions and blockers. `Blocker` and `BlockerState` with `Pending`, `Released` and `Cancelled` are in `smithay/src/wayland/compositor/transaction.rs:53`. A `Barrier` helper is at `:70`. Transactions collect surfaces plus blockers (`:111`) and support `add_blocker` (`:164`), `merge_into` (`:174`), `finalize` (`:207`), global readiness in `Transaction::state` (`:236`), application in `apply` (`:261`), and per-client ordering in `TransactionQueue` (`:280`). The header comment (`:1`) describes synchronized subsurfaces merging into the parent pending transaction and future explicit sync blockers. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 634 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 635 | Public hooks are `add_pre_commit_hook`, `remove_pre_commit_hook` and `add_blocker` (`smithay/src/wayland/compositor/mod.rs:454`, `:547`), backed by `PrivateSurfaceData` (`smithay/src/wayland/compositor/tree.rs:188`). `wl_surface.commit` invokes pre-commit hooks then commits (`smithay/src/wayland/compositor/handlers.rs:266`). |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 636 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 637 | Dmabuf readiness uses `Dmabuf::generate_blocker` returning `DmabufBlocker` plus `DmabufSource` (`smithay/src/backend/allocator/dmabuf.rs:267`), with the `Blocker` impl at `:524`. Explicit sync uses acquire and release points stored in `DrmSyncobjSurfaceCachedState` (`smithay/src/wayland/drm_syncobj/mod.rs:96`), validated as pairs (`:242`), installed by pre-commit hook (`:330`), and waited on through `DrmSyncPoint::generate_blocker` plus `DrmSyncPointBlocker` (`smithay/src/wayland/drm_syncobj/sync_point.rs:240`, `:324`). Multiple surfaces can join one transaction through `PendingTransaction::merge_into` and synchronized subsurface grouping. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 638 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 639 | ### 7.6 Presentation and timing protocols |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 640 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 641 | `src/wayland` contains `presentation` (presentation-time), `fifo` (fifo-v1), `commit_timing` (commit-timing-v1), `drm_syncobj` (linux-drm-syncobj-v1), `content_type` (content-type-v1) and `alpha_modifier` (alpha-modifier-v1) (`smithay/src/wayland/mod.rs:50`). No `tearing_control` or `color_management` modules exist, so tearing-control-v1 and color-management-v1 have no dedicated smithay helpers in this checkout. |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 642 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 643 | ### 7.7 Allocator |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 644 | |
57f44a63d99f | atagen | 2026-10-16 05:34 UTC | 645 | Common docs and traits are in `smithay/src/backend/allocator/mod.rs:1`, with submodules `dmabuf`, `dumb`, `format`, `gbm`, `udmabuf`, `vulkan` and `swapchain` (`:18`), and the `Allocator` plus `Buffer` traits (`:44`, `:60`). Concrete types are `GbmAllocator` (`smithay/src/backend/allocator/gbm.rs:147`), `DumbBuffer` (`smithay/src/backend/allocator/dumb.rs:17`), `VulkanAllocator` (`smithay/src/backend/allocator/vulkan/mod.rs:123`), `VulkanImage` (`:382`), `Swapchain` (`smithay/src/backend/allocator/swapchain.rs:46`) and `Slot` (`:74`), plus `Dmabuf` in `dmabuf.rs`. The Vulkan allocator targets up to Vulkan 1.3 and requires `VK_EXT_image_drm_format_modifier`, `VK_EXT_external_memory_dmabuf` and `VK_KHR_external_memory_fd`, with optional `VK_EXT_4444_formats` (`smithay/src/backend/allocator/vulkan/mod.rs:1`). |