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.
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, and this hasn’t been implemented yet. 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 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.
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
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 Conflictsfirstname.lastname@example.org Afteremail@example.com # 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.