feat(linux/wlgrab): report HDR from the output's image description - #5615
feat(linux/wlgrab): report HDR from the output's image description#5615superuser404notfound wants to merge 1 commit into
Conversation
c1e06c7 to
708c9f8
Compare
|
Pushed a revision for the SonarCloud gate. Of the 26 findings, 10 were fair and are fixed; the other 16 are the shape of the Wayland C protocol and are marked rather than worked around. Fixed
Marked with
Re-checked after the change: still compiles at The two Read the Docs failures look unrelated to this change: both builds end in |
708c9f8 to
ae2a529
Compare
display_t::is_hdr() defaults to false in platform/common.h and is overridden in two places: kmsgrab, from the connector's HDR_OUTPUT_METADATA property, and the PipeWire path, from the SPA colorimetry. wlgrab overrides neither, so colorspace_from_client_config() always takes the SDR branch and a client asking for HDR over capture = wlr receives a 10-bit encode of Rec. 709. That is the right answer today, because the backend has no way to know better. It does not have to stay that way: colour-management-v1 publishes the output's whole image description to any client that asks, it carries more than the DRM property does, and it is available on a virtual output exactly as it is on a physical one. So bind wp_color_manager_v1, read the captured output's image description once when the capture is set up, and answer is_hdr() and get_hdr_metadata() from it. This is the job pipewire.cpp already does with the SPA colorimetry, over the Wayland protocol instead. Bound at version 1 deliberately: everything read here is in the first version, and a later one only adds events that would need handlers. The unit conversions are commented where they happen. The protocol carries CIE 1931 coordinates multiplied by a million and SS_HDR_METADATA carries them multiplied by fifty thousand; the luminances already agree, minimum in ten-thousandths of a nit and the rest in whole nits. A compositor without the protocol, or one that will not describe the output, leaves the colour unknown, which reads as SDR everywhere it is used - the behaviour every wlroots compositor had before this existed.
ae2a529 to
af9b521
Compare
|



What this changes
display_t::is_hdr()defaults tofalseinplatform/common.hand is overridden in two places:kmsgrab.cpp, from the connector'sHDR_OUTPUT_METADATAproperty, andpipewire.cpp, from the SPA colorimetry.wlgrab.cppoverrides neither, socolorspace_from_client_config()always takes the SDR branch:A client that asks for HDR over
capture = wlrtherefore gets a 10-bit encode of Rec. 709 and is correctly told HDR is off.That is the right answer today, because the backend has no way to know better. It does not have to stay that way: colour-management-v1 publishes the output's whole image description to any client that asks, it carries more than the DRM property does, and it is available on a virtual output exactly as on a physical one.
So this binds
wp_color_manager_v1, reads the captured output's image description once when the capture is set up — which is also every moment the answer could have changed, since the encode session is rebuilt on reconnect and on reinit — and answersis_hdr()andget_hdr_metadata()from it. It is the jobpipewire.cppalready does with the SPA colorimetry, over the Wayland protocol instead.Bound at version 1 deliberately: everything read here is in the first version, and a later one only adds events that would need handlers.
Fallback
A compositor without the protocol, or one that will not describe the output, leaves the colour unknown, which reads as SDR everywhere it is used. That is the behaviour every wlroots compositor had before this existed, so nothing regresses.
Testing
Compiles at
-Wall -Werroragainst protocol headers generated from wayland-protocols 1.41 and 1.49, which is version 1 and version 3 ofwp_color_manager_v1; the designated initialisers are there so it survives both, since 1.49 adds aready2event and grows the listener struct.The metadata conversion is checked against BT.2020's red primary, 0.708 and 0.292, which has to come out as 35400 and 14600 in
SS_HDR_METADATA's units.On hardware: a headless sway 1.12 session on the Vulkan renderer, in an Incus container, on an RTX 4080 under the proprietary driver, streaming to a Moonlight client with HDR enabled.
The picture is correct, checked by eye and not only in the log. The output was at 2250x1206 at 120 Hz, adopted from the client mid-stream, so HDR survives a mode change.
One dependency worth stating
This reports what the compositor says. For a headless output to be able to say anything, wlroots has to accept that a virtual output can present BT.2020 and PQ, which it does not today — the capability is read from a monitor's EDID and a headless output has no monitor. That is a ten-line change and is in flight separately at https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5453.
On a compositor whose output can already be in HDR, this change stands on its own.