Gnome 的 Fractional Scaling¶
背景¶
最近发现部分软件(包括 Google Chrome,Firefox 和 Visual Studio Code)在 125% 的 Fractional Scaling 模式下会很卡。找到了一些临时解决方法,但是很不优雅,也很麻烦。所以深入研究了一下 Fractional Scaling 的工作方式。
临时解决方法¶
根据关键字,找到了 Chrome menus too slow after enabling fractional scaling in Ubuntu 20.04。按它的方法,关闭 Google Chrome 的硬件加速,发现卡顿问题确实解决了。
类似地,也可以关闭 VSCode 的硬件加速,在 Firefox 里也可以找到相应的设置。这样操作确实可以解决问题。但是,对于每一个出问题的应用都这样搞一遍,还是挺麻烦的。
另一个思路是,不使用 Fractional Scaling,而只是把字体变大。但毕竟和我们想要的效果不大一样。
一些发现¶
在物理机进行了一些实验以后,发现一个现象:125% 的时候卡顿,而其他比例(100%,150%,175%,200%)都不卡顿。
网上一顿搜到,找到了 xrandr 工具。下面是观察到的一些现象(GNOME 设置分辨率一直是 1920x1080):
放缩比例 | xrandr 显示的分辨率 | xrandr 显示的 transform |
---|---|---|
100% | 1920x1080 | diag(1.0, 1.0, 1.0) |
125% | 3072x1728 | diag(1.6, 1.6, 1.0) |
150% | 2560x1440 | diag(1.33, 1.33, 1.0) |
175% | 2208x1242 | diag(1.15, 1.15, 1.0) |
200% | 1920x1080 | diag(1.0, 1.0, 1.0) |
在 xrandr 文档 中,写了:transform 是一个 3x3 矩阵,矩阵乘以输出的点的坐标得到图形缓存里面的坐标。
由此可以猜想:fractional scaling 的工作方式是,把绘制的 buffer 调大,然后再用 transform 把最终输出分辨率调成 1920x1080。可以看到,xrandr 显示的分辨率除以 transform 对应的值,就是 1920x1080。但这并不能解释 100% 和 200% 的区别,所以肯定还漏了什么信息。
翻了翻 mutter 实现 fractional scaling 的 pr,找到了实现 scale 的一部分:
if (clutter_actor_get_resource_scale (priv->actor, &resource_scale) &&
resource_scale != 1.0f)
{
float paint_scale = 1.0f / resource_scale;
cogl_matrix_scale (&modelview, paint_scale, paint_scale, 1);
}
然后找到了一段对 scale 做 ceiling 的代码:
if (_clutter_actor_get_real_resource_scale (priv->actor, &resource_scale))
{
ceiled_resource_scale = ceilf (resource_scale);
stage_width *= ceiled_resource_scale;
stage_height *= ceiled_resource_scale;
}
这样,100% 和其他比例就区分开了。
另外,也在代码 中发现:
#define SCALE_FACTORS_PER_INTEGER 4
#define SCALE_FACTORS_STEPS (1.0 / (float) SCALE_FACTORS_PER_INTEGER)
#define MINIMUM_SCALE_FACTOR 1.0f
#define MAXIMUM_SCALE_FACTOR 4.0f
这段代码规定了比例只能是 25% 的倍数。
我也试了一下用 xrandr --scale 1.5x1.5:效果就是窗口看起来都更小了,分辨率变成了 2880x1620,transform 是 diag(1.5, 1.5, 1.0)。
虚拟机测试¶
接着,用虚拟机做了一些测试。为了在 GNOME over Wayland 上使用 fractional scaling,需要运行:
接着又做了类似上面的测试(GNOME 设置分辨率一直是 2560x1600):
放缩比例 | xrandr 显示的分辨率 |
---|---|
100% | 2560x1600 |
125% | 2048x1280 |
150% | 1704x1065 |
175% | 1464x915 |
200% | 1280x800 |
在这个测试中,xrandr 显示的 transform 一直都是单位矩阵;还用了来自 xyproto/wallutils 的 wayinfo
命令查看输出的分辨率,一直是 2560x1600,DPI 一直是 96。用 wallutils 的 xinfo 看到的结果和 xrandr 一致(通过 XWayland)。但是和物理机有一点不同:物理机有一个选项问要不要打开 fractional scaling,下面还会提示性能下降的问题;但是虚拟机上并没有这个提示,而是直接给了一些 Scale 比例的选项。
尝试了一下,在 GNOME over X11 上是找不到 fractional scaling 的(没有出现设置 scale 的选项)。找到一个实现这个功能的 fork:https://github.com/puxplaying/mutter-x11-scaling,不过没有尝试过。
我也尝试在虚拟机中用 xrandr --scale,结果就是输出黑屏,需要重启 gdm 来恢复到登录界面。
更新:由于物理机使用的是 Ubuntu,想到是不是 Ubuntu 采用了上面那个 fork 的 patch,然后就在 changelog 中看到:
mutter (3.38.1-1ubuntu1) groovy; urgency=medium
* Merge with debian, including new upstream version, remaining changes:
- debian/gbp.conf: update upstream branch to point to ubuntu/master
- debian/patches/x11-Add-support-for-fractional-scaling-using-Randr.patch:
+ X11: Add support for fractional scaling using Randr
* d/p/clutter-backend-x11-Don-t-set-the-font-dpi-computed-on-X1.patch:
- Dropped, applied upstream
也找到了对应的 patch 文件。这也就解释了,为什么网上会说 GNOME over X11 支持 fractional scaling,并且需要用 gsettings 打开,而我在 Debian 和 Arch Linux 上设置这个选项也没有用了。原来是 Ubuntu 加的私货啊。
在 patch 中,找到了这么一段配置的解释:
+ <key name="fractional-scale-mode" enum="org.gnome.mutter.X11.scale-mode">
+ <default>"scale-ui-down"</default>
+ <description>
+ Choose the scaling mode to be used under X11 via Randr extension.
+
+ Supported methods are:
+
+ • “scale-up” — Scale everything up to the requested scale, shrinking
+ the UI. The applications will look blurry when scaling
+ at higher values and the resolution will be lowered.
+ • “scale-ui-down — Scale up the UI toolkits to the closest integer
+ scaling value upwards, while scale down the display
+ to match the requested scaling level.
+ It increases the resolution of the logical display.
+ </description>
+ </key>
这样就可以解释前面看到的现象了:默认是 scale-ui-down
,也就是先放大到两倍(closest integer scaling value upwards),再缩小(scale down the display to match the requested scaling level)。