fix(linux): stop the HDR watchdog from firing after synchronous no-op transactions

On a Wayland HDR session, colors flickered between HDR and washed-out SDR every ~5 seconds: the mpv-leg timeout in apply_hdr_state was armed after SetHdrOutput returned, so a synchronous reply (the no-op short-circuit that runs on every playback restart and re-describe) orphaned the timer. Five seconds later it fired against a healthy plane and withdrew the live HDR image description; the next re-apply re-attached it and armed the next orphan.

Arm the timeout only while the reply is genuinely outstanding. An asynchronous reply still removes it, and a genuinely wedged core is still bounded.

Verified in a headless-sway Docker repro against the same PQ/BT.2020 file: 2.15.0 logs the false 'mpv never answered the output colour-space switch' warning 5 s after plane bring-up and again after source recognition; the fixed build logs none across bring-up, HDR playback, and seeks.

close #2016
This commit is contained in:
edde746
2026-08-19 06:07:25 +02:00
parent 05ef93c55b
commit 4b6533d25b
+10 -3
View File
@@ -622,9 +622,16 @@ static void apply_hdr_state(MpvPlugin* self, bool allow, mpv::HdrToneMapping mod
// The surface's own watchdog bounds this leg too, but it only unstages
// the plane - the plugin's transaction state and the queued HDR
// method calls stay stuck behind the unanswered reply. This timeout
// answers them. Armed after SetHdrOutput so a synchronous reply (the
// no-op short-circuit) cannot race it, and removed by the reply
// callback above.
// answers them, and is armed only while the reply is genuinely
// outstanding. A synchronous reply - the no-op short-circuit, or a
// player that cannot command output properties - has already finished
// the leg by this line, and a timer armed for it would be an orphan
// nothing removes: the reply callback above ran before the source id
// existed. That orphan fired five seconds after every no-op re-apply
// (one per playback restart) and withdrew the plane's live HDR
// description each time - the HDR/SDR flicker of issue #2016. An
// asynchronous reply removes the timer in the reply callback.
if (*leg_finished) return;
struct MpvLegTimeout {
MpvPlugin* self;
guint64 generation;