fix(host): the console reported the resolution the client asked for, not the one it got

`/api/v1/local/summary` (and the console card behind it) read the live-stats mode
slot, which bring-up seeded from the NEGOTIATED mode:

    let live_mode = Arc::new(AtomicU64::new(pack_mode(
        mode.width, mode.height, interval_hz(interval))));

The refresh was already corrected there — the comment says so, because KWin caps
a virtual output's rate — but the SIZE was still the request. Only a mid-stream
resize ever fixed it: the rebuild path below publishes `delivered_mode(frame..)`,
and bring-up never did.

Attach is what makes this matter rather than being pedantry. On a box with a
physical display the gamescope backend logs

    gamescope: box drives a physical display — attaching at its own mode (no
    re-mode) client_w=5120 client_h=1440

and streams the panel's size. Measured on home-nobara-1 with a 1080p HDMI panel
attached: the capture negotiated 1920x1080 and NVENC opened 1920x1080@240, while
the summary reported 5120x1440 — the console confidently naming a resolution
nobody was watching, which is exactly the shape of the stale attach-path report
noted on .41 in July ("reusing w=5120 h=1440" while the session was really 1080p).

Seeding the slot from `delivered_mode(frame.width, frame.height, interval)` uses
the same helper the rebuild path already trusts, and changes only the two fields
that were wrong — its refresh term IS `interval_hz(interval)`, so that half is
bit-for-bit what it was.

This publishes the STATS slot only. It deliberately does not send the client a
corrective `Reconfigured`: that remains owed exactly where it already was, under
`adopted_at_bringup`, because an ordinary connect's mode came from the Welcome
rather than from an accept the client has already acted on.

Verified on home-nobara-1, attach session against a 1080p panel:
  summary session:   {"width":1920,"height":1080,"fps":240}
  actually captured: pipewire format negotiated width=1920 height=1080
Before the change the same session reported 5120x1440.
This commit is contained in:
2026-08-10 07:55:18 +02:00
parent 5b3ea6e8db
commit a23c028492
+14 -3
View File
@@ -1899,10 +1899,21 @@ pub(super) fn virtual_stream(ctx: SessionContext, prepared: Option<PreparedDispl
// a stats capture armed after a resize registers the real mode. Seeded with the refresh the
// initial build actually achieved (`interval_hz`), not the request — KWin may cap a virtual
// output at 60 Hz.
// …and seeded with the SIZE the build actually delivered too, not just the refresh. Attach is
// what made the asymmetry visible: `gamescope: box drives a physical display — attaching at its
// own mode (no re-mode)` streams the panel's size, so a client that asked for 5120x1440 is
// really watching 1920x1080 while `/api/v1/local/summary` echoed the request straight back and
// the console reported a resolution nobody was looking at. The rebuild path below already
// publishes `delivered_mode`; bring-up simply never did, so only a mid-stream resize ever
// corrected it. This publishes the stats slot ONLY — it deliberately does not send the client a
// corrective `Reconfigured`, which stays owed exactly where it already was (`adopted_at_bringup`
// above): an ordinary connect's mode came from the Welcome, not from an accept the client has
// acted on, so it is not owed one.
let delivered = delivered_mode(frame.width, frame.height, interval);
let live_mode = Arc::new(AtomicU64::new(pack_mode(
mode.width,
mode.height,
interval_hz(interval),
delivered.width,
delivered.height,
delivered.refresh_hz,
)));
// One-shot force-keyframe flag driven by the management API (`POST /session/idr`, the web-console
// Dashboard's "Request IDR" button) — drained in the encode loop below exactly like a client