AMD Graphics and Sharpness of External Monitor
Solution 1:
I've searched a bit online and saw a pattern with people having problems with some Dell monitors and amdgpu on Linux. Basically, if you notice bad contours/sharpness and bleeding red colors on a Dell monitor, this is likely the issue.
Whatever the brand, if your monitor supports YPbPr (component) input, amdgpu will prioritize this pixel format over RGB on HDMI outputs (for whatever reason). I noticed in my monitor's settings that YPbPr was selected and when setting it to RGB, the colors were completely off. The setting also automatically "restored" itself on every reboot as soon as the kernel loaded.
Apparently, this is also a potential issue on Windows systems, but the Windows AMD graphics driver has a native setting to change the pixel format, while the Linux driver does not, unfortunally. (Up until 5.10)
In order to force RGB pixel format, you need to do these three things:
- Copy your monitor's EDID binary
- Edit the binary to disable YPbPr-input
- Load the modified binary on boot
The process was a bit difficult to work out, but the execution is relatively simple and should take less time than it looks like.
Also, you will have to do steps 1 and 2 just once per monitor and can then repeat only step 3 whenever you should install a new system.
1. Copy your monitor's EDID binary (Source)
Your monitor sends metadata (called "EDID") that is saved in a binary on your system partition. You find the location of that binary via Terminal:
find /sys/devices/pci*/*/*/*/card*/*HDMI* -name "*edid*"
The output will look something like this, your numbers may be different:
/sys/devices/pci0000:00/0000:00:08.1/0000:05:00.0/drm/card0/card0-HDMI-A-1/edid
If you have multiple HDMI displays, you can enter xrandr
to try to determine which one is the first by its resolution. Otherwise, the one that displays your boot and logon screens is the first display. When in doubt, you can also temporarily unplug the ones that don't cause issues.
Once you have determined your faulty HDMI monitor, maybe create a new directory in your home folder and copy the file there:
mkdir EDID
cp /sys/devices/<YOUR-PATH>/drm/card0/card0-HDMI-A-1/edid EDID/<YOUR-MONITOR-MODEL>-edid.bin
(Assuming that HDMI-A-1 causes issues - replace those segments with your own path and maybe name your file according to your monitor's model.)
2. Edit the binary to disable YPbPr-input
Now you have made a copy of your monitor's EDID file, but since it's a binary, you need specific software to edit it.
Right now, you will have to download wxEDID from Sourceforge: https://sourceforge.net/projects/wxedid/
The source is in Debian's repository, but there is unfortunately no package in Debian or Ubuntu at this point (June '21), so you have to build it yourself.
First, install the necessary development packages:
sudo apt update && sudo apt install libwxgtk3.0-gtk3-dev
Then, unpack the wxEDID source archive you downloaded and open a Terminal within that directory.
./configure --prefix=$HOME
make
make install
(This will build and install wxEDID into your home directory, you can remove it later or even build it on a live system.)
After that, open a new Terminal and start wxEDID:
bin/wxedid
In wxEDID, open your monitor's copied EDID-file, likely to sit in your user's home/EDID. Then edit the following lines as necessary:
SPF: Supported features
- vsig_format
= 0b00
CHD: CEA-861 header
- YCbCr 4:2:2
& YCbCr 4:4:4
= 0
VSD: Vendor Specific Data Block
- DC_Y444
= 0
Afterward, select Option
and Assemble EDID
from the menu. Then save the modified file, like so <YOUR-MONITOR-MODEL>-edid-rgb.bin
If you should need your modified EDID file for your monitor again, you can copy and store it now.
3. Load the modified binary on boot (Source)
To load it into your system, first create a directory with root-permissions:
sudo mkdir -p /lib/firmware/edid
Then then copy the modified file there, also with root permissions:
sudo cp EDID/<YOUR-MONITOR-MODEL>-edid-rgb.bin /lib/firmware/edid/
After that, you'll have to add loading of the file to your kernel boot commands, e.g. via GRUB:
sudo nano /etc/default/grub
Edit the line GRUB_CMDLINE_LINUX_DEFAULT=
to include:
drm.edid_firmware=HDMI-A-1:edid/<YOUR-MONITOR-MODEL>-edid-rgb.bin
after quiet splash
.
(This assumes that your faulty display was HDMI-A-1 in the beginning, else, change the number accordingly.)
Then, save and close the file with Ctrl + O and Ctrl + X and reload GRUB:
sudo update-grub
Lastly, you have to add an initramfs-hook to load the custom firmware, else you will receive errors in your boot log. Create a new file:
sudo touch /etc/initramfs-tools/hooks/edid
Open it:
sudo nano /etc/initramfs-tools/hooks/edid
Enter the following code:
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
# Begin real processing below this line
mkdir -p "${DESTDIR}/lib/firmware/edid"
cp -a /lib/firmware/edid/<YOUR-MONITOR-MODEL>-edid-rgb.bin "${DESTDIR}/lib/firmware/edid/<YOUR-MONITOR-MODEL>-edid-rgb.bin"
exit 0
(Again, replace the binary paths with your monitor's modified EDID files.)
Then, save and close this file as well and make it executable:
sudo chmod +x /etc/initramfs-tools/hooks/edid
Finally, update your initramfs:
sudo update-initramfs -u
Now, all you need to do is reboot (I had to do a full shutdown and turn off the monitor once) and the display quality should be good.
I hope this issue will be fixed in future driver releases, especially since the Windows driver supports manual selection of pixel formats. Unfortunately, since the issue has existed for a while now, this workaround may still be necessary for Dell owners and other users in the future, if they notice it.