Fix washed out colors on Linux with Xorg/Wayland display server and Intel/AMD video cards
Most common monitors nowadays have 1920x1080 resolution, same as HD TVs. When this resolution is available, some video card drivers, on Linux, will output limited RGB pixel ranges, considering the monitor as a TV. Instead of 8-bit per color (0 to 255), the video card outputs a limited range of 16 to 235 which causes washed out colors, with less bright white and less dark black. This may not be obvious at first sight, especially for regular users when switching to a new monitor.
Unfortunately, there is no straight fix for this issue on Ubuntu (or other Linux distributions). There are no options in settings app. More than that, the way of fixing this has changed with the new Ubuntu 21.04 which uses Wayland instead of Xorg display server. In this post I will show you how to address this issue on both display servers and get the expected picture colors on your HDMI monitor with Ubuntu.
I have experienced this issue on Intel UHD Graphics 630, but there are also reports about AMD cards. Ubuntu users with NVIDIA cards should be able to change this setting from NVIDIA Settings.
Display server
The first thing to do is check whether your distribution uses Xorg (xrandr) or Wayland. You can get information about the running display server with the following command[1]:
ps -e | grep tty
Or, at least on Ubuntu, you may try to use xrandr
to detect monitors.
xrandr --listmonitors
If the first command reports gdm-wayland-ses
or the second XWAYLAND0
, then you're using Wayland. Otherwise, if you see Xorg
in the output of first, then you will be using xrandr
to configure monitors. Following is the fix for both servers. Follow only the instructions for your server!
For reference, here is my output on Ubuntu 21.04 Wayland:
~$ xrandr --listmonitors Monitors: 1 0: +*XWAYLAND0 1920/520x1080/290+0+0 XWAYLAND0
And here is the output when I switch to Xorg:
~$ xrandr --listmonitors Monitors: 1 0: +*HDMI-1 1920/521x1080/293+0+0 HDMI-1
Xorg
Identify monitor connections using the above command to list monitors. In my case, the "connector" is XWAYLAND0
, however I cannot change display properties using xrandr
on Wayland. If using Xorg, connector names can be: HDMI1, HDMI-1, HDMI-1-1, HDMI-A-1, LVDS1, LVDS-1, DP1, DP-1 etc. Open a terminal as regular user and run one of the following commands depending on video card. Make sure you adjust connector name.
- For Intel:
xrandr --output HDMI-1 --set "Broadcast RGB" "Full"
Picture quality problems appear whenever there is a mismatch between what the video card outputs and what the monitor expects/supports. Just in case, the limited range is selected with:
xrandr --output HDMI-x --set "Broadcast RGB" "Limited 16:235"
- For AMD:
xrandr --output HDMI-x --set "output_csc" "bypass"
If this doesn't get you proper picture quality, try other settings[2]:
xrandr --output HDMI-x --set "output_csc" "tvrgb" xrandr --output HDMI-x --set "output_csc" "ycbcr601" xrandr --output HDMI-x --set "output_csc" "ycbcr709"
The result is instant, but not permanent. After reboot, it reverts to default mode. But we can create a script, write this command in it and run it at every boot[3]. It is easier to add this command to Startup Applications. Launch it (gnome-session-properties
) add add your command. Write whatever you want in the other fields.
Add xrandr display setting command to Startup Applications
This should be all for Xorg users.
Wayland
Wayland server makes this setting more difficult to change and dangerous. This part is based on the instructions provided by Brad T. Laue (see reference [4]). Let's install the prerequisites (libdrm-tests
):
sudo apt update && sudo apt install libdrm-tests
Run proptest
in a regular terminal. Here is a truncated output of my device:
trying to open device 'i915'...done Connector 74 (HDMI-A-1) 1 EDID: flags: immutable blob blobs: value: 00ffffffffffff00410cd1c0668a0000 ... 000000000000000000000000000000f9 ... 76 Broadcast RGB: flags: enum enums: Automatic=0 Full=1 Limited 16:235=2 value: 1 ... Connector 84 (HDMI-A-2) 1 EDID: flags: immutable blob blobs: value: ... 76 Broadcast RGB: flags: enum enums: Automatic=0 Full=1 Limited 16:235=2 value: 0 ...
Let's see what is important here:
- The device name:
i915
(this is the name of the Intel Graphics driver for Linux) - The connector IDs:
74
for HDMI-A-1 with non-empty EDID. Where EDID data exists, a monitor is connected. There is nothing connected to HDMI-A-2 (connector 84). - The property ID:
76
for Broadcast RGB (property name would have beenoutput_csc
on AMD card). - The possible values for the property: 0, 1 and 2. Note value 1 already set by me to connector 74.
With this output in the terminal, open a text editor and let's make the correct command. The proptest
utility gets installed to /usr/bin
. The syntax is:
proptest -M <driver_name> -D <device> <ID_of_connector> connector <ID_of_property> <value>
Connector and property numbers vary depending on hardware. So, in my case, for the connected monitor:
/usr/bin/proptest -M i915 -D /dev/dri/card0 74 connector 76 1
Picture quality problems appear whenever there is a mismatch between what the video card outputs and what the monitor expects/supports. Therefore you should try value 2 if you don't get desired results. But, how do you get the results? Running the command in terminal does nothing. That is because it must run before display manager starts. Note that running the command in TTY console will have immediate results.
In /etc/systemd/system
there is a file display-manager.service
. On Ubuntu 21.04, this is a link to /lib/systemd/system/gdm3.service
, so this is the file I will edit. First of all, a backup is highly recommended. Then, we can use nano to add this command to be executed before GDM starts.
sudo cp /lib/systemd/system/gdm3.service /lib/systemd/system/gdm3.service.bak sudo nano /lib/systemd/system/gdm3.service
Find [Service]
section and add an extra ExecStartPre
entry before any other entries.
ExecStartPre=-/usr/bin/proptest -M i915 -D /dev/dri/card0 74 connector 76 1
Adjust this command as needed, with the correct driver name, connector and property IDs. Here is my modified GDM service configuration:
Modified GDM3 service configuration for proptest
Commands from ExecStartPre
are executed before the main process starts. Multiple entries are allowed and commands are executed in order, one after the other. The -
in front of the executable to run is very important because it tells systemd to continue in case the command returns an error code. Otherwise, the service would not start.
The proptest
utility uses DRM_IOCTL
to change GPU settings. DRM is the acronym for Direct Rendering Manager.
This should be all. Reboot and see the difference.
Troubleshooting
- Nothing changed
Run proptest
again. What is the value of Broadcast RGB/output_csc parameter? If it is still default 0, you must see what went wrong with the command. In a terminal, run systemctl status gdm3
. The output will be something like:
gdm3.service - GNOME Display Manager Loaded: loaded (/lib/systemd/system/gdm3.service; indirect; vendor preset: enabled) Active: active (running) since Sun 2021-08-01 23:31:40 EEST; 13min ago Process: 2460 ExecStartPre=/usr/bin/proptest -M i915 -D /dev/dri/card0 74 connector 76 1 (code=exited, status=0/SUCCESS) Process: 2461 ExecStartPre=/usr/share/gdm/generate-config (code=exited, status=0/SUCCESS) Process: 2464 ExecStartPre=/usr/libexec/gdm-wait-for-drm (code=exited, status=0/SUCCESS) Main PID: 2465 (gdm3) Tasks: 3 (limit: 9306) Memory: 2.9M CGroup: /system.slice/gdm3.service └─2465 /usr/sbin/gdm3
If the error code is not 0, further investigation is needed.
- Credentials error
Nothing is changed and the when you check the status of GDM, you find the following error, with exit code 243:
Process: 815 ExecStartPre=/usr/bin/proptest -M i915 -D /dev/dri/card0 74 connector 76 1 (code=exited, status=243/CREDENTIALS)
I have no idea at this time how to fix this issue. All I can tell you is that if you restart GDM it will work for the current session. Use:
sudo service gdm3 restart
- GDM no longer starts
This is the worst case. Press Ctrl+Alt+Fx, where Fx can be anything from F3 to F6 to get to console. Log in by entering username and password. Then you may use either nano as you did previously and remove the line you added or you may restore the original file. Here are the commands for both of these approaches:
sudo rm /lib/systemd/system/gdm3.service sudo cp /lib/systemd/system/gdm3.service.bak /lib/systemd/system/gdm3.service sudo nano /lib/systemd/system/gdm3.service
Reboot with sudo reboot
or attempt to (re)start GDM3.
Conclusions
Although it is common nowadays to connect the PC to monitor using HDMI, the method of adjusting display color range on Linux is still difficult. More than that, the methods depend on video card type, display server and sometimes the results are inconsistent.
The method for Wayland worked for me a few times, it now fails without me changing anything. I'm getting the credentials error exit code.
What else to do? Until a permanent fix appears, some of you can try to use a different connection method. I could use a DVI cable since both PC and monitor support it. I could also use a HDMI to DVI cable/adapter.
References
- loved.by.Jesus. Answer on How to get information about which display server is running? on Unix & Linux StackExchange
- George. Answer on xrandr — how to find the correct RGB full spectrum output command for my system on AskUbuntu StackExchange
- Tejas Lotlikar. Answer on How to save xrandr options? on AskUbuntu StackExchange
- Brad T. Laue. Quick Tip: Setting the Color Space Value in Wayland (2017).
This is super helpful, my eyes can rest now
ReplyDeleteI've tried writing script under /etc/X11/Xsession.d but didn't work
The Wayland method seems does not work for AMD GPUs.
ReplyDeleteThe Xorg method also doesn't work for AMD GPUs.
ReplyDeleteIs there a way to change this setting on Nvidia using the open source Nouveau drivers?
ReplyDeleteMy machine always outputs Full range, but I need to set it to Limited so it will look correct on my TV.
Every article and forum thread I've found on this topic, only talk about how to do it with Intel and AMD, but absolutely nothing about Nouveau.
(I can't use the proprietary Nvidia driver, because I'm using Retroarch in DRM/KMS mode, which only works with Nouveau. Also, the Nvidia drivers are quite buggy in my experience.)
Hi! I think I found a solution to (y)our (code=exited, status=243/CREDENTIALS) error. Bear in mind: I'm on Fedora 35 GNOME, I have no other way to test this solution, even a VM is useless: any feedback is welcome!
ReplyDeleteI followed more or less your approach, but instead of editing directly gdm.service I created a new service from scratch only to launch proptest. Oh, BTW, editing services in /usr/lib/ like you did is discouraged, as these files may change with distro updates: you should always create drop-in files with "systemctl edit service_name.service").
That said, here's the proptest.service content (placed in /etc/systemd/system/):
[Unit]
Description=Launch proptest and set fullRGB by default
# Hard dependency: "Start proptest before starting gdm"
After=systemd-user-sessions.service
Before=gdm.service
[Service]
ExecStart=-/usr/bin/proptest -M i915 -D /dev/dri/card0 85 connector 80 1
[Install]
WantedBy=multi-user.target
The "magic" is in the line "After=systemd-user-sessions.service".
Honestly, I cannot understand deeply in detail why my line solves the issue. Like, I get that the problem is somewhat related to having a session already opened before the display manager starts, but other than that I sincerely don't understand why your solution (which seems to do the same) does not work.
In any case, let me know if this works for you, if it does it would be really awesome having contributed to your blog.
(And thank you for this post, without it I would have never tried to solve the issue!)
Awesome! Thank you very much! I will try this and see if it works for me too.
DeleteThanks a lot! Fedora 38 Works great
DeleteThank you so much! It changed to 1 now!
DeleteIt seems that (code=exited, status=243/CREDENTIALS) error has nothing to do with credentias. It is just the exit code of /usr/bin/proptest and systemd assuming it follows the convention for exit status codes (https://www.freedesktop.org/software/systemd/man/systemd.exec.html#id-1.21.8)
ReplyDeleteIt seems that somehow proptest at boot conflicts with plymouth-start.service. I edited proptest.service and now it seems to work consistently:
ReplyDelete[Unit]
Description=Launch proptest and set fullRGB by default
DefaultDependencies=no
After=systemd-modules-load.service
Before=plymouth-start.service
[Service]
ExecStart=-/usr/bin/proptest -M i915 125 connector 98 1
I found a solution: use proptest to set full RGB.
ReplyDeleteSteps in Ubuntu:
sudo apt install libdrm-tests
Create an udev trigger:
create file "/etc/udev/rules.d/80-local.rules" with content (replace CONNECTOR with connector number, which can be found executing "proptest" command):
ACTION=="add", SUBSYSTEM=="module", KERNEL=="i915", RUN+="/usr/bin/proptest -M i915 CONNECTOR connector 98 1"
This Udev rule execute proptest command right after i915 module is loaded.
I found a solution: use proptest to set full RGB.
ReplyDeleteSteps in Ubuntu:
sudo apt install libdrm-tests
Create an udev trigger:
create file "/etc/udev/rules.d/80-local.rules" with content (replace CONNECTOR with connector number, which can be found executing "proptest" command):
ACTION=="add", SUBSYSTEM=="module", KERNEL=="i915", RUN+="/usr/bin/proptest -M i915 CONNECTOR connector 98 1"
This Udev rule execute proptest command right after i915 module is loaded.
Better way of doing it and works for Arch and also on other distros. https://www.wezm.net/v2/posts/2020/linux-amdgpu-pixel-format/#the-fix
ReplyDeleteThis is very helpful. I spent almost 2 days trying to figure this out.Now my second monitor works as expected. Thank you very much! Great job!
ReplyDeleteUnfortunately it's not working for Fedora 40 on Wayland, no method seems to work. Not even from the TTY console; as soon as one logs in, everything reverts. How can something so trivial be so hard to set... It's a pity because I can't use Wayland as my 2nd monitor has completely washed out colors.
ReplyDelete