@@ -127,28 +127,41 @@
(`cmake-build-release-cuda`), `E2E_ENCODER=nvenc E2E_WIDTH=1920 E2E_HEIGHT=1080 E2E_FPS=60
E2E_FRAMES=600`, KVM, guest framebuffer 640x400 scaled by Sunshine, ~330 samples per run.
| Build | Transport (QEMU) | Encoder | p50 (3 runs) | p95 (3 runs) |
|----------------------------|----------------------------|---------------|--------------------|--------------------|
| before (`98cb3d22`) | shared memory map (11.1.1) | NVENC | 13.5 / 11.1 / 13.6 | 21.0 / 18.6 / 21.8 |
| after (damage-driven) | shared memory map (11.1.1) | NVENC | 4.0 / 4.5 / 3.9 | 9.8 / 10.0 / 9.4 |
| after (damage-driven) | D-Bus messages (8.2.2) | NVENC | 3.9 | 8.7 |
| Build | Transport (QEMU) | Encoder | p50 (runs) | p95 (runs) |
|--------------------------------|----------------------------|---------------|--------------------------|--------------------------|
| before (`98cb3d22`) | shared memory map (11.1.1) | NVENC | 13.5 / 11.1 / 13.6 | 21.0 / 18.6 / 21.8 |
| before, rerun at the end | shared memory map (11.1.1) | NVENC | 10.9 / 13.7 | 17.8 / 20.5 |
| damage-driven (`225def94`) | shared memory map (11.1.1) | NVENC | 4.0 / 4.5 / 3.9 / 4.0 | 9.8 / 10.0 / 9.4 / 4.5 |
| damage-driven (`225def94`) | D-Bus messages (8.2.2) | NVENC | 3.9 | 8.7 |
| damage-driven (`225def94`) | shared memory map (11.1.1) | software x264 | 4.4 | 6.4 |
| final phase-1 capture | shared memory map (11.1.1) | NVENC | 3.9 / 3.9 / 3.9 / 3.8 / 4.0 / 3.9 | 4.4 / 5.4 / 5.1 / 4.6 / 4.4 / 4.7 |
| after (damage-driven) | shared memory map (11.1.1) | software x264 | 4.4 | 6.4 |
The shm + hardware encoder target from #3 (p95 ≤ 12 ms at 1080p60) is met: p95 went from ~21 ms to
~10 ms. The remaining p95 is NVENC plus the RAM→CUDA upload of the 1080p frame; x264 is faster on
this mostly static 640x400 guest picture scaled up. Unit tests pin the behavior:
`QemuCaptureTest.PushesDamageWithinMillisecondsNotAtTheNextTick` fails on the old loop (median
The shm + hardware encoder target from #3 (p95 ≤ 12 ms at 1080p60) is met: p95 went from 18-22 ms
to 4-10 ms, p50 from 11-14 ms to ~4 ms. The spread of the "after" p95 (4.4 vs ~10 ms for the same
binary) is host load: the first three runs overlapped with other agents' work on this machine;
rerunning that binary on a quiet host gave 4.5 ms. The remaining ~4 ms is the RAM→CUDA upload and
NVENC. Unit tests pin the behavior: `QemuCaptureTest.PushesDamageWithinMillisecondsNotAtTheNextTick`
fails on the old loop (median 26 ms at 30 fps) and passes now; `BurstsOfDamagePushAtMostOneFramePerInterval`
and `NoDamageRepeatsNoFrames` pass on both.
26 ms at 30 fps) and passes now, `BurstsOfDamagePushAtMostOneFramePerInterval` and
`NoDamageRepeatsNoFrames` pass on both.
### Mode changes, cursor and console selection (REQ-CAP-004/005/006)
- **Reboot during a stream** (`E2E_RESET_AFTER_FRAMES=30 E2E_FRAMES=60`, Debug build, software
encoding): PASS on QEMU 11.1.1 (map path; the firmware's 720x400 text mode and the guest's
640x400 mode each re-create the display, longest gap between decoded frames 143-167 ms) and on
QEMU 8.2.2 (message path; longest gap 64 ms). On 8.2 Sunshine logged no size change during the
reset, so no display re-creation happened; I assume its VGA BIOS text mode is also 640x400 but
didn't check it with a screendump.
- **Reboot during a stream** (`E2E_RESET_AFTER_FRAMES`): the script sends QMP `system_reset`,
waits for QEMU's `RESET` event, then requires more decoded frames, the pattern again, at least
10 picture changes after the reset (the square blinks, so a frozen stream fails), a bounded gap
between frames and at least `E2E_RESET_MIN_DISPLAYS` (3) displays created during the stream.
The first version of the guest switched to mode 13h immediately, so whether a reset produced a
720x400 text scanout was timing-dependent (seen in one run, not in the next ones). `pattern.S`
now stays in text mode for one second (`int 15h`, AH=86h), so every reboot changes the size
twice. Results with that guest:
- QEMU 11.1.1, Debug, software: PASS, 4 displays during the stream, 35 picture changes after the
reset, longest frame gap 172 ms.
- QEMU 11.1.1, Release, NVENC, 1080p60: PASS, 3 displays, longest gap 231 ms.
- QEMU 8.2.2, Debug, software, `E2E_RESET_MIN_DISPLAYS=1`: PASS, 31 picture changes, gap 61 ms.
QEMU 8.2's D-Bus display never sends the VGA text-mode scanout: a Python listener on the same
VM saw only `Scanout 640x480` at registration and `Scanout 640x400` after the reset, while a QMP
`screendump` taken during the reset was 720x400. So on 8.2 a reboot doesn't re-create the
display; that's QEMU, not the backend.
- Disable keeps the display and pushes a black frame; the next update at the same size brings the
picture back. Size changes still return `reinit` (unit tests replay Disable → firmware size → OS
size).