Greetings!

We're currently implementing RandR 1.5 in Qt, and in that work popped up the 
age old question of DPI, so I thought I'd check with the horse's mouth, so to 
speak :)

I've read the very informative post by Alex on why EDID is not trustworthy [1], 
and other related materials, but I may have misunderstood things, so please 
correct me if I'm wrong!

Now, the question from Qt's side is what we should report from QScreen's 
physicalDpi() and logicalDpi() on X [2]. The former being the actual DPI of the 
glass/panel, and the latter  a "virtual DPI", affected by OS decisions such as 
multiplying the physical DPI with 1.3 to account for viewing distance, rounding 
it to common fixed values, or based on user preference.

For reference, macOS has a fixed logical DPI of 72, whereas Windows allows the 
user to set the logical DPI in various (possibly fractional) increments of 96 
DPI.

(Both OSes allow us to also get the physical DPI (however inaccurate it is from 
EDID), which we report as physicalDpi(), e.g. for users who want to draw 
graphics they can put a ruler up to their screen and compare against.)

Now, in the past this logical DPI was mostly relevant for how to draw text, but 
nowadays this is also how platforms like Windows deals with high-DPI panels. 
Setting a scale of 200% in the Windows display preferences results in Windows 
reporting 192DPI to us, which we in turn report to the user as a device 
independent coordinate system with a 96DPI and 2.0 device pixel ratio, 
resulting in scaled text, and UI.

Now, for X, there's at least four different things to consider, as far as I can 
tell:

    1) The resolution and size of the X Screen
    2) The resolution and size of the individual outputs
    3) The resolution and size of the RandR 1.5 monitors
    4) The Xft.DPI setting.

(For all the things exposed through RandR (1-3), as far as I can tell they are 
all stored as resolution and size (in mm), so all DPI-numbers going in or out 
of X are effectively converted to a width and height in mm to represent that 
DPI with the current resolution taken into account.)

The last one is the easy one, it's clearly a logical DPI, and we reflect that 
in Qt if set. Unfortunately it's a global DPI.

Now, I'm guessing that #1, as set by Xorg -dpi, xorg.conf DisplaySize, or 
xrandr --dpi, originally was meant as a physical DPI override, for cases where 
the detection and heuristics in X would fail? But nowadays, especially with a 
single X Screen representing multiple physical displays, with potentially 
different physical DPIs, it feels like it's effectively a logical DPI setting 
on an X level, with the same limitation as Xft.DPI in that it's a global 
setting. What is your take on this?

If it's the former — a physical DPI override (however little that makes sense 
when reflecting multiple displays) — we don't want to reflect it per QScreen, 
as that would not be specific enough in a multi monitor setup. Nor do we want 
to reflect it for a QScreen's logicalDpi, if it's strictly defined as a 
physical property, not to be used for adjusting logical DPI.

But if it's in practice the latter — a logical DPI override — then we should 
reflect it through a QScreen's logicalDpi, if Xft.DPI hasn't been set to 
override it.

Now, for #2, as far as I can tell there isn't any option in xrandr to override 
this, nor does tweaking DisplaySize in xorg.conf affect it (even for multiple 
Monitor sections), so I'm guessing it's strictly a physical size picked up from 
EDID? If that's not the case, and it's possible to override it for the user, 
then the same questions as for #1 apply: Does that make it a logical DPI?

Finally, for #3, this is where it gets interesting. From reading the RandR spec 
[3] about the new Monitors introduced in 1.5, this seems like a defined logical 
DPI:

    "This new object separates the physical configuration of the hardware
    from the logical subsets of the screen that applications should
    consider as single viewable areas."

It's possible to combine two outputs into one monitor, to split a single output 
into multiple monitors, or even to override the auto-generated monitor for a an 
output. And all these allow you to pass a width and height, effectively setting 
the DPI. E.g.

  xrandr --setmonitor DUMMY0-DPIOVERRIDE 1600/200x1200/200+0+0 DUMMY0

This seems like the definition of logical DPI, where the desktop environment 
can give the user a nice control panel on how to adjust these things, either 
directly by adding/removing/moving monitors, or by setting a DPI or scale (200% 
e.g.) on an individual monitor, and then reflect that as RandR updates.

Based on all of this, it seems Qt should do the following:

  1. If Xft.DPI has been set, respect that as a global override, and reflect 
that as the logical DPI for all QScreens
  2. If not, reflect the resolution and size of individual RandR 1.5 monitors 
as logical DPI per QScreen
  3. If 1.5 is not available, reflect the resolution and size of the X Screen 
as a global logical DPI for all QScreens
  4. Reflect the resolution and size of the individual outputs as physical DPI, 
or read EDID ourselves

As far as I can tell this should cover DEs like Ubuntu 20.04 that sets a global 
192 Xft.DPI to represent 200% scaling (and fractional scales in between 100% 
and 200%), as well as DEs that (in the future) allow per-monitor DPI/scale 
control via the 1.5 monitors.

Thanks for reading this far! Let me know if I missed something, and what your 
thoughts are :)

Cheers,
Tor Arne

[1] https://lists.fedoraproject.org/pipermail/devel/2011-October/157671.html
[2] https://doc.qt.io/qt-5/qscreen.html#logicalDotsPerInch-prop
[3] 
https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/raw/master/randrproto.txt


_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to