HiDPI on dual 4K monitors with Linux

Vincent Bernat

I have been using a Lenovo ThinkPad X1 Carbon laptop (210 DPI) for four years and a Nokia 8 phone (550 DPI) for a year. I enjoy their HiDPI screens: the text is crisp and easy to read. To get a similar experience for my workstation, I bought a pair of Dell P2415Q monitors:

Two Dell P2415Q
Dual screen setup with two Dell P2415Q monitors

Monitors#

The Dell P2415Q is a 24″ display featuring an IPS panel with a 3840×2160 resolution (185 DPI) and complete coverage of the sRGB color space. It was released in 2015 and its price is now below US$400. It received positive reviews.

One of my units arrived with a dead pixel. I thought it was a problem from the past but Dell policy on dead pixels says:

During LCD manufacturing process, it is not uncommon for one or more sub-pixels to become fixed in an unchanging state. A display with a 1 to 5 fixed sub-pixel is considered normal and within industry standards.

Update (2018-12)

Three new dead pixels have appeared. Therefore, I do not recommend these screens.

Another issue is the presence of faint horizontal gray lines, (barely) visible on white background. The issue seems to not be uncommon but Dell is dismissive about it. If I sit correctly, the lines become invisible.

Update (2020-06)

This happens when the screen is connected through HDMI. In this case, the pixel format may be YCbCr of RGB. I have fixed the problem by hacking the EDID of the display so the driver chooses RGB.

I am a bit disappointed by these issues, but I think they are bearable and it is an opportunity to help fix my obsession over such details.

Graphics card#

To drive a 4K display at 60 Hz, you need at least either HDMI 2.0 or DisplayPort 1.2. The Dell P2415Q has been upgraded to HDMI 2.0 in 2016 and also provides a DP 1.2 input. There is a port for daisy-chaining a second monitor but, without support for DP 1.3, the refresh rate would drop to 30 Hz.

There is currently no available Radeon card around US$100 able to drive two 4K displays. On the NVIDIA side, the GeForce GT 1030 fits the bill with a power consumption of 20 W for the DDR4 version. I opted for a passively cooled model from MSI. On Linux, the result is quite disappointing:

  • The nouveau driver has still rudimentary support for this generation of NVIDIA chips. The result was unbearably slow and the HDMI 2.0 port was not handled correctly.

  • The proprietary NVIDIA driver exhibits poor performance. It’s difficult to know if this is due to the graphic card itself,1 or to the drivers. I’ve tested 390, 396, 410, 415, and 418. Moreover, suspend-to-RAM is broken.

Update (2019-05)

I have switched to an ASUS Phoenix Radeon RX 550. With such a card, everything runs smoothly, using the open-source driver amdgpu. The card comes with a fan but it is PWM-controlled. See ArchWiki for more details. In automatic mode, when /sys/class/drm/card0/device/hwmon/hwmon1/pwm1_enable is set to 2, it spins at 1050 RPM:

$ sensors amdgpu-pci-0100
amdgpu-pci-0100
Adapter: PCI adapter
vddgfx:       +0.88 V
fan1:        1047 RPM
temp1:        +51.0°C  (crit = +94.0°C, hyst = -273.1°C)
power1:       17.20 W  (cap =  35.00 W)

HiDPI support on Linux with X11#

GNOME and KDE now support HiDPI displays out of the box when running with X11. For other environments, it’s quite easy to setup, thanks to xsettingsd. The following snippet should be invoked from ~/.xsession or when the DPI value changes:

# Target DPI
dpi=192

# For applications supporting XSettings, `Xft/DPI' sets font scaling
# (and sometimes interface scaling), `Gdk/WindowScalingFactor' sets
# interface scaling with GTK 3, and `Gdk/UnscaledDPI' undo font scaling
# for GTK 3 applications.
> ~/.xsettingsd cat <<EOF
Xft/DPI $(( $dpi*1024 ))
Gdk/WindowScalingFactor $(( $dpi/96 ))
Gdk/UnscaledDPI $(( $dpi*1024/($dpi/96) ))
EOF
pkill -HUP xsettingsd || xsettingsd &

# For Qt applications.
export QT_AUTO_SCREEN_SCALE_FACTOR=1
export QT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough

# For miscellaneous applications.
echo Xft.dpi: $dpi | xrdb -merge

Then, it is up to each application to know how to render on a HiDPI display. The table below gives an overview of HiDPI support for various ones, using the above settings. “Text scaling” indicates if an application can adapt the font size. This is usually the most essential feature. “Interface scaling” tells if it can scale the whole interface, including the icons. Ideally, applications are also expected to be able to dynamically update scaling when notified through XSettings, which is useful when switching to an external display.

Application Text scaling Interface scaling No restart needed?
Most Qt 5 apps
Chromium2
Firefox (GTK 3)
Most Electron apps3
Emacs 26.1 (GTK 3) 😐
Emacs 27.1 (GTK 3 with Cairo) 😐
VTE terminals (GTK 3) 😐
Blender4
Gimp (GTK 2)
Inkscape (GTK 2)
Most GTK 2 apps
Most GTK 3 apps 😐
Most Java apps5 🙄 🙄
xterm and rxvt (with Xft) n/a
Most other applications

Qt 5 applications offer very good support. GTK 3 applications can currently only scale their interfaces using an integer factor, which is annoying when you need a 1.5× factor. GTK 2 applications will only scale the text and there are still many of them—notably Gimp. For more details, have a look at the dedicated page on ArchWiki. Beyond X11, Wayland can provide per-monitor scaling6 and to scale applications without HiDPI support.

In conclusion, today’s situation still depends heavily on the applications you run. As I spend most of my time in a VTE terminal, Emacs and, Firefox, I am mostly happy with the result.


  1. Compared to my previous setup, the number of pixels is quadrupled. The card is using 4-lane links over PCI 3.0 which translates to a bandwidth of 25 Gbits/s. This barely allows the transfer of 7680×2160 pixels at 60 Hz using 24-bit colors. Also, the use of DDR4 for such a graphic card is seen as a cheap move↩︎

  2. To detect changes, Chromium watches for RandR events. They may be caught before XSettings variables are updated. ↩︎

  3. If it doesn’t work, try with the --force-device-scale-factor=2 flag. ↩︎

  4. Blender relies on the Xft.dpi resource value↩︎

  5. Java applications need to be invoked with the GDK_SCALE=2 environment variable. Otherwise, they don’t scale. ↩︎

  6. Qt also supports mixed DPI with QT_AUTO_SCREEN_SCALE_FACTOR=1 and QT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough. GTK does not, but screens with lower DPI can be rendered up with a higher resolution and scaled down with the --scale option of xrandr. See “Mixed DPI and the X Window System” for more details and “Configuring mixed DPI monitors with xrandr” for a focus on how to use xrandr↩︎