Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More reliable pixendensitydetection under Xorg/Randr #5178

Merged
merged 6 commits into from
Jan 10, 2021
Merged

More reliable pixendensitydetection under Xorg/Randr #5178

merged 6 commits into from
Jan 10, 2021

Conversation

robinxan
Copy link
Contributor

What does the pull request do?

Physical monitor dimensions are parsed from the monitors EDID instead of requesting them from Randr.
Automatic pixeldensity detection locks to specific scalingfactors (100%, 125%,150%,175%,200%) and falls back to 100% if internal values are way off (scalingfactor higher than 300%) or no EDID is found.

What is the current behavior?

Xrandr reports unreliable physical monitor dimensions with hacky/invalid EDIDs, e.g. no physical dimension for specific modes.
This can lead to scalingfactors of 1000% and higher.

What is the updated/expected behavior with this PR?

  • Detect the pixeldensity more reliable and don't overscale.
  • Select a scalingfactor from a list of predefined scalingfactors similar to Windows (100%,125%,150%,175%.200%).

How was the solution implemented (if it's not obvious)?

  • Get the EDID via XRRListOutputProperties and XRRGetOutputProperty. Code Reference from Chromium
  • Parse width and height (in cm) from the Basic Display Parameters, as these values should be more likely to be correct than the modespecific dimension.Wikipedia Reference

Checklist

Breaking changes

Fixed issues

Fixes #5124

Physical dimensions are parsed from the monitors EDID instead of Randr.
GuessPixelDensity locks to fixed values, caps at 2 and returns 1 if the supplied
dimensions are unreasonable.
@dnfadmin
Copy link

dnfadmin commented Dec 14, 2020

CLA assistant check
All CLA requirements met.

{
if(rrOutput == IntPtr.Zero)
return null;
var output = Marshal.ReadInt64(rrOutput);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that it's 64 bit on 32-bit ARM too? Might be better to use ReadIntPtr

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, _XRRMonitorInfo is defined like this:

typedef struct _XRRMonitorInfo {
    Atom name;
    Bool primary;
    Bool automatic;
    int noutput;
    int x;
    int y;
    int width;
    int height;
    int mwidth;
    int mheight;
    RROutput *outputs;
} XRRMonitorInfo;

and RROutput is a XID, so we should make the Outputs property to be IntPtr*

src/Avalonia.X11/X11Screens.cs Outdated Show resolved Hide resolved
if(!hasEDID)
return null;
XRRGetOutputProperty(_x11.Display, output, _x11.Atoms.RR_PROPERTY_RANDR_EDID, 0, 128, false, false, _x11.Atoms.AnyPropertyType, out int actualType, out int actualFormat, out int nItems, out _, out IntPtr prop);
if(actualType != 19) // XA_INTEGER
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XA_INTEGER is defined in X11Atoms class and Atom enum

XFree(new IntPtr(properties));
if(edid.Length < 22)
return null;
var width = edid[21];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since those are magic numbers, please, quote the standard, e. g.

// 15h 1 Max. Horizontal Image Size cm.
// 16h 1 Max. Vertical Image Size cm.

density = X11Screen.GuessPixelDensity(mon.Width, mon.MWidth);
}

var pSize = GetPhysicalMonitorSizeFromEDID(mon.Outputs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should also check NOutputs to be >= 1. BTW, any idea why it can be more than 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be the case if the user creates an monitor with multiple outputs attache by running something like this:

$ xrandr --setmonitor DP-2-1 auto DP-2,HDMI-1
$ xrandr --listmonitors
Monitors: 1
 0: DP-2-1 5120/0x1440/1+0+0  DP-2 HDMI-1

So detecting the smallest scaling factor among the attached outputs should be safest way to handle this case.

@kekekeks
Copy link
Member

kekekeks commented Dec 14, 2020

It would be nice to also get the actual monitor name from EDID too, so we could have a more fine-grained override via environment variable (obviously that's outside of the scope of this PR)

At some point we might also define a user-wide/system-wide config and a configuration utility like Qt does.

Robin Dostal and others added 2 commits December 20, 2020 23:19
Change XRRMonitorInfo.Outputs from IntPtr to IntPtr* and iterate over
all Outputs to detect the smallest pixeldensity.
@kekekeks kekekeks added this to the 0.10 milestone Jan 1, 2021
@danwalmsley danwalmsley merged commit 13e0e30 into AvaloniaUI:master Jan 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash at start with 5120x1440 on linux
5 participants