# Why the landscape drawers were janky, and the fix — 2026-10-13 Operator, after the landscape install: "it works but it's kinda janky here where it wasn't before ... (the two drawers at least)". After the fix: "ok yeah it's plenty fast now". ## Method Board: the second T-Display-K230, one Linux core (CPU0 belongs to the coprocessor), Sway with Pixman. `rotation-bench/bench.sh` arms the card compositor's telemetry (`swaymsg card_shell benchmark injected`) and runs `rotation-bench/abrun.sh`: three rounds of a bottom-edge swipe to the Drawer, `--surface hide`, a top-edge pull to the Shade, `--surface hide`, with 1.5 s settles. Touches are injected through `tools/inject-tap.sh` on an `evemu-device` clone. sway and shell-ui CPU come from `/proc//stat` (100 Hz ticks). Frame intervals are the gaps under 400 ms between consecutive `event=present presented=1` rows, so they cover animation frames, not idle time. `frame-damage` shows every frame in every mode damaging the full 699,776-pixel output. The injector forks one `evemu-event` per axis write on the same core, so absolute rates are below what a finger sees. All modes pay that cost equally. ## Result | Run (log) | Output | Renderer | Frames | Median interval | p90 | sway CPU | | --- | --- | --- | --- | --- | --- | --- | | `landscape.log` | 1232×568, transform 270 | stock Pixman | 75 | 287 ms (3.5 fps) | 307 ms | 10.14 s | | `quarter.log` | same | `WLR_PIXMAN_QUARTER_TURN=1` | 127 | 153 ms (6.5 fps) | 287 ms | 8.09 s | | `output.log` | same | `WLR_PIXMAN_OUTPUT_TURN=1` | 160 | 115 ms (8.7 fps) | 172 ms | 5.01 s | | `portrait.log` | 568×1232, transform normal (live `swaymsg`) | stock Pixman | 169 | 96 ms (10.4 fps) | 172 ms | 3.44 s | | `installed.log` | landscape, installed profile | `WLR_PIXMAN_OUTPUT_TURN=1` | 158 | 115 ms (8.7 fps) | 172 ms | 4.96 s | shell-ui used 0.57–0.84 s in every run; its own Home frame is about 10 ms. The jank was the compositor's per-frame software rotation. Stock Pixman applies the 270° transform to every layer it composites (wallpaper, Home, the overlay), which takes the slow transformed-fetch path. The output-turn renderer composes the logical frame normally and rotates it into the physical buffer once. The first three landscape rows and `portrait.log` ran on one build, a non-persistent trial with the patched wlroots (`card-shell-hdmi-trial`), and switched renderers with a `/run` drop-in. `landscape.log` ran on the installed stock wlroots before that trial. `installed.log` is the installed profile after the change below, with no runtime overrides. ## The change When `k230.shell.panelTransform` is not `normal`, `nix/shell.nix` now builds the card compositor against the patched wlroots and sets `WLR_PIXMAN_OUTPUT_TURN=1`, `WLR_PIXMAN_QUARTER_TURN=0`. The portrait default's toplevel derivation is unchanged (`v8bj22rb…`, evaluated before and after). The HDMI quarter-turn trial is untouched. ## Limits `docs/evidence/hdmi-shell-performance/README.md` records the output-turn path as an open HDMI experiment. Nearest-filter output was byte-exact in its probes. Scaled bilinear textures can differ by up to three ARGB8888 channel steps from stock per-texture rotation. Landscape panel content is drawn unscaled, but no pixel-exact panel comparison was made here. The camera frame and native captures show the orientation and layout, and the operator's report covers the feel. No frame budget is claimed.