With Qt5 gaining support for high-DPI displays, and applications starting to exercise that support, it’s easy for applications to suddenly become unusable with some screens. For example, my old Samsung TV reported itself as 7″ screen. While this used not to really matter with websites forcing you to force the resolution of 96 DPI, the high-DPI applications started scaling themselves to occupy most of my screen, with elements becoming really huge (and ugly, apparently due to some poor scaling).
It turns out that it is really hard to find a solution for this. Most of the guides and tips are focused either on proprietary drivers or on getting custom resolutions. The DisplaySize specification in xorg.conf apparently did not change anything either. Finally, I was able to resolve the issue by overriding the EDID data for my screen. This guide explains how I did it.
Step 1: dump EDID data
Firstly, you need to get the EDID data from your monitor. Supposedly read-edid tool could be used for this purpose but it did not work for me. With only a little bit more effort, you can get it e.g. from xrandr:
$ xrandr --verbose [...] HDMI-0 connected primary 1920x1080+0+0 (0x57) normal (normal left inverted right x axis y axis) 708mm x 398mm [...] EDID: 00ffffffffffff004c2dfb0400000000 2f120103804728780aee91a3544c9926 0f5054bdef80714f8100814081809500 950fb300a940023a801871382d40582c 4500c48e2100001e662150b051001b30 40703600c48e2100001e000000fd0018 4b1a5117000a2020202020200000000a 0053414d53554e470a20202020200143 020323f14b901f041305140312202122 2309070783010000e2000f67030c0010 00b82d011d007251d01e206e285500c4 8e2100001e011d00bc52d01e20b82855 40c48e2100001e011d8018711c162058 2c2500c48e2100009e011d80d0721c16 20102c2580c48e2100009e0000000000 00000000000000000000000000000029 [...]
If you have multiple displays connected, make sure to use the EDID for the one you’re overriding. Copy the hexdump and convert it to a binary blob. You can do this by passing it through xxd -p -r (installed by vim).
Step 2: fix screen dimensions
Once you have the EDID blob ready, you need to update the screen dimensions inside it. Initially, I did it using hex editor which involved finding all the occurrences, updating them (and manually encoding into the weird split-integers) and correcting the checksums. Then, I’ve written edid-fixdim so you wouldn’t have to repeat that experience.
First, use --get option to verify that your EDID is supported correctly:
$ edid-fixdim -g edid.bin EDID structure: 71 cm x 40 cm Detailed timing desc: 708 mm x 398 mm Detailed timing desc: 708 mm x 398 mm CEA EDID found Detailed timing desc: 708 mm x 398 mm Detailed timing desc: 708 mm x 398 mm Detailed timing desc: 708 mm x 398 mm Detailed timing desc: 708 mm x 398 mm
So your EDID consists of basic EDID structure, followed by one extension block. The screen dimensions are stored in 7 different blocks you’d have to update, and referenced in two checksums. The tool will take care of updating it all for you, so just pass the correct dimensions to --set:
$ edid-fixdim -s 1600x900 edid.bin EDID structure updated to 160 cm x 90 cm Detailed timing desc updated to 1600 mm x 900 mm Detailed timing desc updated to 1600 mm x 900 mm CEA EDID found Detailed timing desc updated to 1600 mm x 900 mm Detailed timing desc updated to 1600 mm x 900 mm Detailed timing desc updated to 1600 mm x 900 mm Detailed timing desc updated to 1600 mm x 900 mm
Afterwards, you can use --get again to verify that the changes were made correctly.
Step 3: overriding EDID data
Now it’s just the matter of putting the override in motion. First, make sure to enable CONFIG_DRM_LOAD_EDID_FIRMWARE in your kernel:
Device Drivers ---> Graphics support ---> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) ---> [*] Allow to specify an EDID data set instead of probing for it
Then, determine the correct connector name. You can find it in dmesg output:
$ dmesg | grep -C 1 Connector [ 15.192088] [drm] ib test on ring 5 succeeded [ 15.193461] [drm] Radeon Display Connectors [ 15.193524] [drm] Connector 0: [ 15.193580] [drm] HDMI-A-1 -- [ 15.193800] [drm] DFP1: INTERNAL_UNIPHY1 [ 15.193857] [drm] Connector 1: [ 15.193911] [drm] DVI-I-1 -- [ 15.194210] [drm] CRT1: INTERNAL_KLDSCP_DAC1 [ 15.194267] [drm] Connector 2: [ 15.194322] [drm] VGA-1
Copy the new EDID blob into location of your choice inside /lib/firmware:
$ mkdir /lib/firmware/edid $ cp edid.bin /lib/firmware/edid/samsung.bin
Finally, add the override to your kernel command-line:
drm.edid_firmware=HDMI-A-1:edid/samsung.bin
If everything went fine, xrandr should report correct screen dimensions after next reboot, and dmesg should report that EDID override has been loaded:
$ dmesg | grep EDID [ 15.549063] [drm] Got external EDID base block and 1 extension from "edid/samsung.bin" for connector "HDMI-A-1"
If it didn't, check dmesg for error messages.