Quick Tip: Setting the Color Space Value in Wayland

Some televisions and monitors are limited to the “broadcast RGB” color range. This is a subset of an 8-bit range of levels from 0-255 - in this case, 16-235. You’ll find this referred to as 16:235 in some cases. You can find a lot more on this here: http://kodi.wiki/view/Video_levels_and_color_space If you’re using Xorg this can be adjusted using the xrandr with something along the lines of:


xrandr --output HDMI-0 --set output\_csc tvrgb

for Radeon devices. For Intel cards, it will look like this:


xrandr --output HDMI-0 --set "Broadcast RGB" "Limited 16:235"

So - if you’ve noticed your colors are washed out and were wondering why, the above is a good starting point for you. But wait! There’s more.

Wayland

Maybe you’re like me, and you switched to Wayland. You had solved the above problem in Xorg, but you can’t find a way to do the same thing with Wayland. The short answer: Wayland protocol itself doesn’t provide a facility for this, and the developers are leaving that up to the compositor to manage[1], and this hasn’t been implemented yet[2]. The way to do this is with the ‘proptest’ utility, a test suite built with libdrm. You typically won’t find this distributed anywhere. This solution is hacky but it gets the job done.

Build libdrm

Build the latest libdrm. At the time of this writing that’s 2.4.82. You’ll need requisite build dependencies provided by your distribution. Build it, don’t install it:


./configure && make

From here I fished ‘proptest’ out of ./test/proptest/.lib/ and placed it in /usr/local/bin.

Proptest

If you run the proptest command without arguments you’ll receive a list of connectors and properties.


Usage:
  /root/libdrm-2.4.82/tests/proptest/.libs/proptest \[options\]
  /root/libdrm-2.4.82/tests/proptest/.libs/proptest \[options\] \[obj id\] \[obj type\] \[prop id\] \[value\]

options:
  -D DEVICE  use the given device
  -M MODULE  use the given driver

The first form just prints all the existing properties. The second one is
used to set the value of a specified property. The object type can be one of
the following strings:
  connector crtc

Example:
  proptest 7 connector 2 1
will set property 2 of connector 7 to 1

Among these properties will be the specific one controlling output colorspace. For Intel cards this will be ‘Broadcast RGB’ and for Radeon it will be ‘output_csc’. Nouveau may or may not have a property for this, don’t know. Sample output from my laptop below:


trying to open device 'i915'...done
Connector 48 (eDP-1)
    1 EDID:
        flags: immutable blob
        blobs:

        value:
            00ffffffffffff004d103e1400000000
            28190104a52313780effb3a85334b825
            0c4d5500000001010101010101010101
            0101010101014dd000a0f0703e803020
            35005ac2100000180000000000000000
            00000000000000000000000000fe0037
            50485054824c51313536443100000000
            0002410328001200000b010a20200019
    2 DPMS:
        flags: enum
        enums: On=0 Standby=1 Suspend=2 Off=3
        value: 0
    5 link-status:
        flags: enum
        enums: Good=0 Bad=1
        value: 0
    52 audio:
        flags: enum
        enums: force-dvi=18446744073709551614 off=18446744073709551615 auto=0 on=1
        value: 0
    53 Broadcast RGB:
        flags: enum
        enums: Automatic=0 Full=1 Limited 16:235=2
        value: 0
    54 scaling mode:
        flags: enum
        enums: None=0 Full=1 Center=2 Full aspect=3
        value: 3

In my case, property 53 is the ‘Broadcast RGB’ property. These numbers will vary on your own system. Based on all of the above, you’d need to run:


proptest -M i915 -D /dev/dri/card0 48 connector 53 2

Caveat

This doesn’t seem to take effect while Wayland is running, it has to be run beforehand.

Putting it all together

Since I use GNOME I made a copy of ‘gdm.service’ in /etc/systemd/system and made the following addition:


ExecStartPre=/usr/local/bin/proptest proptest -M i915 -D /dev/dri/card0 48 connector 53 2

So that the entire unit looks like:


\[Unit\]
Description=GNOME Display Manager

# replaces the getty
Conflicts=getty@tty7.service
After=getty@tty7.service

# replaces plymouth-quit since it quits plymouth on its own
Conflicts=
After=

# Needs all the dependencies of the services it's replacing
# pulled from getty@.service and
# (except for plymouth-quit-wait.service since it waits until
# plymouth is quit, which we do)
After=rc-local.service plymouth-start.service systemd-user-sessions.service

# GDM takes responsibility for stopping plymouth, so if it fails
# for any reason, make sure plymouth still stops
OnFailure=plymouth-quit.service

\[Service\]
ExecStartPre=/usr/local/bin/proptest proptest -M i915 -D /dev/dri/card0 48 connector 53 2
ExecStart=/usr/sbin/gdm
KillMode=mixed
Restart=always
IgnoreSIGPIPE=no
BusName=org.gnome.DisplayManager
StandardOutput=syslog
StandardError=inherit
EnvironmentFile=-/etc/locale.conf

\[Install\]
Alias=display-manager.service

I disabled the gdm service with ‘systemctl disable gdm’ and used ‘systemctl enable gdm’ to enable my edited unit file - units in /etc/systemd/system override the other paths. This did the trick for me. As you can see the process is pretty raw - you can tell some aspects of Wayland are not yet mature. I’m confident they will be though soon enough, and this solved my last blocker to using it full time. Hope this helps somebody out there.