Фикс DPI на Linux + nVidia
Проблема
Несколько лет назад приобрел монитор с IPS матрицей и обычным DPI (Benq BL2411PT). Но сразу после его подключения шрифты и графические элементы мне казались слегка замыленными при включенном сглаживании. Особенно было заметно в Хроме и приложениях на электроне (там они харкодят свои настройки рендеринга шрифтов). Перековырял все настройки шрифтов, настройки монитора, подобрал идеальные шрифты, даже кабеля пробовал другие. Подобрал вроде бы как оптимальные значения. Но все равно ощущение мыла не покидало меня. Причем другие люди не замечали этого «мыла», для них было все отлично. В итоге забил и списал это на мое восприятие IPS матрицы с обычным DPI (на IPS немного другая структура пикселей, до этого у меня были только TN матрицы). Уже начал подумывать о приобретении другого монитора с HiDPI. Но потом как-то глаза привыкли и не вытекали. Только сейчас решил докопаться до истины 🙂
P.S.:
- пост актуален для одномониторной конфигурации (в многомониторной конфигурации будут некоторые отличия);
- используется X-сервер;
- используются проприетарные драйвера nVidia;
- фиксил на Debian 11 + xfce4.
Поиск проблемы
Теоретически «мыло» может создаваться при несоответствии пиксельной сетки монитора тому, что выдает X-сервер.
Находим спецификации монитора:
Видим, что DPI 94, а диагональ 24″.
Проверяем, какой DPI установлен в X-сервере:
$ xrdb -q | grep dpi
В выхлопе пусто, значит DPI не задан жестко в базе.
Посмотрим информацию X-сервера через xdpyinfo (нас интересует dimensions
и resolution
):
$ xdpyinfo | grep 'dimensions\|resolution'
dimensions: 1920x1200 pixels (524x321 millimeters)
resolution: 93x95 dots per inch
Тут видим, что разрешение нормальное, но DPI почему-то уже не 94×94, а 93×95.
Теперь посмотрим через xrandr, в каком режиме подключен и работает монитор:
$ xrandr -q | grep -w connected
DP-0 connected primary 1920x1200+0+0 (normal left inverted right x axis y axis) 518mm x 324mm
Тут видим, что физические размеры экрана (518x324mm) отличаются от тех, что получили от xdpyinfo (524x321mm). Т.е. монитор работает с одним DPI, а X-сервер выдает картинку в другом. Кто же у нас врет? 🙂
WTF?
Копаем глубже. Беглый гуглеж нашел матрицу монитора — LM240WU8-SLD1
.
Тут видим реальные размеры рабочей области матрицы — 518.4x324mm. Значит X-сервер выдает картинку с неверным DPI. Получается изображение выводится на матрицу монитора не пиксель в пиксель.
Параметры изображения X-серверу передает драйвер видеокарты. А драйвер расчитывает DPI сам, либо берет данные с EDID монитора (паспорта монитора). Найдем упоминание DPI в логе X-сервера:
$ grep DPI /var/log/Xorg.0.log<br>[ 43769.535] (--) NVIDIA(0): DPI set to (93, 95); computed from "UseEdidDpi" X config
Здесь мы видим, что драйвер видеокарты запрашивает значение DPI из EDID монитора.
Посмотрим, что у нас прописано в EDID. Нас интересует DTD
(Detailed Timing Descriptors). Проще говоря, это параметры работы матрицы, рекомендуемые производителем. Для этого поставим edid-decode (есть в репозиториях дистрибутивов) для вывода EDID в человекочитаемом виде и проверяем:
$ xrandr --props | edid-decode -c -s | grep DTD
DTD 1: 1920x1200 59.950 Hz 8:5 74.038 kHz 154.000 MHz (518 mm x 324 mm)
DTD 2: 720x480 59.940 Hz 3:2 31.469 kHz 27.000 MHz (518 mm x 324 mm)
DTD 3: 1280x720 60.000 Hz 16:9 45.000 kHz 74.250 MHz (518 mm x 324 mm)
DTD 4: 720x480 59.940 Hz 3:2 31.469 kHz 27.000 MHz (518 mm x 324 mm)
DTD 5: 720x576 50.000 Hz 5:4 31.250 kHz 27.000 MHz (518 mm x 324 mm)
Рекомендуемые режимы расположены в порядке приоритета. Тут видим, что первый режим соответствуют параметрам матрицы в спецификации. Значит виноват драйвер. Могу только предположить, что он обращается к EDID монитора, игнорирует рекомендуемые параметры, берет другую информацию о дисплее. На основе этих данных расчитывает другие размеры матрицы и по ним неверно расчитывает DPI.
Решение проблемы
Чтобы это пофиксить, нужно везде принудительно указать правильный DPI.
Передаем правильный DPI в базу X-сервера:
$ echo "Xft.dpi: 94" >> ~/.Xresources
$ xrdb -merge ~/.Xresources
Заставим все приложения использовать нужный DPI после запуска X-сервера:
echo "xrandr --dpi 94" >> ~/.xsessionrc
Если в DE есть возможность указания кастомного DPI, то меняем значение на корректное или вообще отключаем. Например, в xfce4 DPI указывается в настройках шрифтов:
Теперь заставим драйвер использовать наш DPI. Для этого установим nvidia-xconfig (если еще не стоит). И с помощью него сгенерируем конфиг X-сервера, который будем править:
$ sudo nvidia-xconfig
Он создаст базовый конфиг в /etc/X11/xorg.conf
. Скопируем этот конфиг в конфиги X-сервера:
$ sudo cp /etc/X11/xorg.conf /usr/share/X11/xorg.conf.d/20-nvidia.conf
Теперь открываем скопированный файл любимым текстовым редактором и вставляем в секцию Device
такие строчки:
Option "UseEdidDpi" "False"
Option "DPI" "94 x 94"
Должно получится примерно так:
Section "Device"
Identifier "Device0"
Driver "nvidia"
VendorName "NVIDIA Corporation"
Option "UseEdidDpi" "False"
Option "DPI" "94 x 94"
EndSection
Теперь выходим из сессии, авторизуемся и проверяем:
$ xdpyinfo | grep 'dimensions\|resolution'
dimensions: 1920x1200 pixels (518x324 millimeters)
resolution: 94x94 dots per inch
$ xrandr -q | grep -iw 'screen\|connected'
Screen 0: minimum 8 x 8, current 1920 x 1200, maximum 32767 x 32767
DP-0 connected primary 1920x1200+0+0 (normal left inverted right x axis y axis) 518mm x 324mm
$ grep DPI /var/log/Xorg.0.log
[ 46562.124] (**) NVIDIA(0): Option "DPI" "94 x 94"
[ 46562.539] (**) NVIDIA(0): DPI set to (94, 94); computed from "DPI" X config option
Все чётко, везде правильные размеры и DPI, а драйвер берет значение из конфига, а не EDID.
После авторизации сразу заметил, что все стало четче и меньше стала заметна радуга в шрифтах, которая актуальна при включении сглаживания шрифтов. В хромобраузерах и проложениях на электроне мыло тоже пропало.