amdv/drm: Dolby Vision output-path fixes#29
Conversation
meson_hdmitx_decide_color_attr() forces subsampled chroma (YUV422, or YUV420 where 4:2:2 is unsupported) at 4K50/60 via is_hdmi4k_support_420(). Dolby Vision cannot tunnel over subsampled chroma: when the DV core raises its VSIF over that base the sink drops the link (no picture). At forced-4K60 there is no resolution change on DV entry, so nothing re-picks a DV-compatible base. Gate the forced subsampling on !is_amdv_enable(): while a DV title is active (Kodi sets dolby_vision_enable per stream, before the DV core turns on) keep 4:4:4 at 4K50/60. The existing colourdepth block then pins RGB/4:4:4 at those VICs to 8-bit, so the base is 4:4:4/8 - a valid DV container the VSIF can land on. Confined to DV via the per-video flag, so SDR/HDR10 keep their subsampled base unchanged (no bandwidth/HDR10 regression).
When Dolby Vision detection fails and the driver falls back to SDR, it re-committed with the stale enhancement-layer flag and metadata still attached, and skipped the core reset that every other format change performs. That could leave a core pointer stranded and smash the kernel stack canary. Build a clean SDR input (dropping the leftover EL fields) and reset the core before re-committing. Signed-off-by: Olivier Allauzen <olivier.allauzen@gmail.com>
At the start of a Dolby Vision title the output-mode policy briefly oscillates BYPASS -> DV -> SDR8 -> DV. The transient DV->SDR8 step, taken while the source is still Dolby Vision, forces an unnecessary core reset with no config commit following it; this leaves an internal core pointer stranded and may be implicated in a rare stack-corruption. Hold the DV output for a few frames when the requested mode drops to SDR while the source is still Dolby Vision, so the spurious away-switch never commits. Genuine changes (the source leaving Dolby Vision, or DV->HDR10/BYPASS) are honored immediately. The hold length is tunable via the amdv_away_from_dv_debounce module parameter (frames to hold; 1 disables it). Signed-off-by: Olivier Allauzen <olivier.allauzen@gmail.com>
| strstr(common->fmt_attr, "422") == NULL && | ||
| strstr(common->fmt_attr, "444") == NULL) { | ||
| if (is_hdmi4k_support_420(vic & 0xff)) { | ||
| if (is_hdmi4k_support_420(vic & 0xff) && !is_amdv_enable()) { |
There was a problem hiding this comment.
This is not need as it is already be checked by hdmi_current_eotf_type.
It get set/reset by vsif package from amdv. So it never reach this place when in DV mode.
There was a problem hiding this comment.
Agreed, on its own in this driver PR is a no-op. A Kodi side fix is needed.
When a Dolby Vision stream starts at the same HDMI timing as the current (SDR) desktop mode, no resolution change occurs, so Kodi never triggers a modeset and the driver keeps the existing SDR color attribute instead of re-deciding it for DV. The DV tunnel is then stuffed into whatever base was already on the wire: at 4K50/60 that's the kernel's forced 10-bit YUV420 base, which is an invalid DV container, so the sink drops the link (audio passes, TV shows no picture). Even when it does lock, the leftover color depth is nondeterministic so the output ends up player-led or TV-led "at random", not matching the user's selection. Both stem from the same gap: DV entry needs to force an HDMI color-attr re-decide to the correct DV base ({444,8}) even when the resolution itself doesn't change.
I can send a Kodi PR with these two changes to make the issue clearer. I'm also happy to work on a better fix if this one doesn't work.
There was a problem hiding this comment.
Not completely true, the case of same resolution but DV/non DV is already covered:
https://github.com/CoreELEC/xbmc/blob/f256069b8a6e43fd2596946dab611fe06271e3aa/xbmc/windowing/amlogic/WinSystemAmlogicGLESContext.cpp#L117
| current_mode = dolby_vision_mode; | ||
| if (amdv_policy_process | ||
| (vf, ¤t_mode, check_format)) { | ||
| if (amdv_honor_output_change( |
There was a problem hiding this comment.
It's caused maybe by the amdv_wait_delay where it wait for default 2 frames to decide if DV or not.
So double checked?
There was a problem hiding this comment.
Good call, I checked it directly. With the debounce compiled out, I swept amdv_wait_delay = 0 / 1 / 2 / 6 and replayed a DV title from the start each time. The BYPASS→DV→SDR8→DV oscillation is identical at every value so it doesn't look that the wait delay produces it:
# amdv_wait_delay=0 (debounce off)
output change from 5 to 1 # BYPASS -> DV (IPT_TUNNEL)
decide_color_attr [eotf:1] => attr[YUV444,8bit]
output change from 1 to 4 # DV -> SDR8 <-- the away excursion
VOUT_EVENT_MODE_CHANGE
output change from 4 to 1 # SDR8 -> DV
output change from 1 to 4 # ...and again
output change from 4 to 1
# amdv_wait_delay = 1, 2, 6: same sequence, same timing
Happy to move to a better layer if you see one, but lowering amdv_wait_delay doesn't remove the excursion.
Three DV output-path fixes: