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

Add the resolution independence book chapter. #913

Merged
merged 4 commits into from
Nov 16, 2020

Conversation

xStrom
Copy link
Member

@xStrom xStrom commented May 10, 2020

As part of my work on #904 I figured I should write something for the book. This chapter gives a quick overview of the pixel density problem and how druid solves it.

@xStrom xStrom added docs concerns documentation S-needs-review waits for review labels May 10, 2020
@jneem
Copy link
Collaborator

jneem commented May 22, 2020

Is there (or will there) be a way to figure out where the physical pixels are? Or at least snap to them? This is an issue when presenting regions in druid-shell, because the system expects a region expressed in an integer number of physical pixels. This means that in order to avoid graphical glitches, druid needs to be able to paint that integer-pixel region with full coverage (i.e., no rounding and anti-aliasing leading to partial coverage at the boundary).

@xStrom
Copy link
Member Author

xStrom commented May 22, 2020

Yes it's possible to determine pixels with almost 100% accuracy. The only issue that I can see right now is if the platform painting context has less precision in calculations (say f32) and we have f64. Even so the chance of it being a practical issue is pretty low I think.

You can use Scale to do conversions.

// If you have a display point Rect and want to know the smallest int Rect that covers it
let rect_px = scale.to_px(&rect_dp); // Turn an arbitrary dp Rect to px Rect
let rect_px_int = rect_px.expand(); // Expand the pixel Rect to integers

// If you have a pixel Rect and want to get it in display points
let rect_dp = scale.to_dp(&rect_px); // Conver to display points
// You're good to go, fractional display points are what you want

@ForLoveOfCats
Copy link
Collaborator

I thoroughly enjoyed reading through this as it greatly helped my understanding of how druid hands paint coords with different screen resolutions. My understanding in this area of druid is far to minimal to give any substantial review but I did want to express my support as it did what it was supposed to do in enlightening me in this area.

CHANGELOG.md Outdated Show resolved Hide resolved
@jneem
Copy link
Collaborator

jneem commented Jun 9, 2020

Is there any reason to wait on this?

will get scaled up by essentially **taking a screenshot of it and enlarging the image.**
This will result in a blurry UI with diagonal and curved lines suffering the most.
There is more hope with fonts where the vector information is still available to the platform,
and instead of scaling up the image the text can be immediately drawn at the larger size.

Choose a reason for hiding this comment

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

Not sure blurry is the right term. At least on a 200% display, Windows uses nearest-neighbour scaling rather than bilinear or such, so it’s just like you had half the resolution, rather than being blurry as such.

I’d tend to say it’s actually text that suffers the most. On Windows by default, either the app is DPI-aware, or the entire thing gets scaled. You can also override the app’s preference and opt into one of these modes (“application” and “system”) if you know how (right click on the executable or shortcut in Explorer, Properties, Compatibility, Change high DPI settings), and there’s a third mode you can choose these days, “system enhanced”, which tries to be clever, matching what you describe, so that sizes mostly get doubled, bitmaps get nearest-neighbour scaled, and GDI text gets rendered perfectly; it works fairly well on some apps (I run BPBible that way: it has minor issues and a few widgets end up half sized, but I’m OK with that), but badly on others (it made Audacity almost entirely half sized and too hard to use; and my experience is that DPI-unaware GTK apps are generally lousy in this mode).

Copy link
Member Author

Choose a reason for hiding this comment

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

Microsoft seems to use blurry and fuzzy to describe the situation. I think it's fine, but if you have specific suggestions for replacement terms, I'm open to considering them.

@nmsmith
Copy link

nmsmith commented Jun 18, 2020

I don't see any description of the size guarantees for a display point. In the absence of further OS scaling (e.g. for accessibility), is a display point defined the same as a CSS reference pixel? i.e. is it the visual angle of one pixel on a device with a pixel density of 96dpi and a distance from the reader of an arm’s length? If we don't have a definition, then a display point could be the size of a hippo 😃

@nmsmith
Copy link

nmsmith commented Jun 18, 2020

Also relevant to this discussion (and the book) is whether the definition of "DPI" in the docs is the dots-per-inch of the physical display device, or a mystical OS-defined DPI intended to trick your app into scaling things up. If it's the former, then we should probably document this. If it's the latter, then it might be worth renaming it to something else for clarity (or even just remove it), for the same reason we're using the term "display points" to prevent terminological confusion.

Edit: Microsoft describes DPI as "dots-per-logical-inch", where logical inches were initially defined as 96 physical pixels and thus detached from any metric or imperial unit. With "DPI scaling", they no longer have a relationship to physical pixels either and thus become an utterly meaningless unit and DPI becomes just a complicated code for "we want you to scale your window content by (100*DPI/96)%".

A mapping (scaling factor) between physical pixels and CSS reference pixels (display points) is the most sensible, and the only thing needed, because (if we are at a standard distance from our devices) it maps pixels to a fixed size relative to our human eyes.

The only other thing Druid might need is the ability to draw at "life size", i.e. in physical units that are never scaled. You need this to draw the ruler tool in the Apple Notes app at the correct size, for example.

@chris-morgan
Copy link

I don’t think it’s something we need worry about; the accepted convention is that you have some sort of base unit which will vary quite substantially by device, purpose, &c. (CSS’s definition is fairly frivolous and grossly inconsistent with reality, even though it’s the most accurate definition ever), and that “DPI” means 96× that (for at least Windows and CSS. (In the distant past 72× was used in some places, with the pixel thus being one point.)

No platform deals in or exposes physical dimensions, because screens don’t expose the true answer. Specialist applications that actually care about physical dimensions (like some graphics programs or potentially desktop publishing software) do calibration themselves. Invariably such things already support zooming, so it’s no particular bother for them to scale it all by whatever calibration factor they determine. I don’t think Druid should touch this space.

The software concept of “DPI” is a historical name that no longer reflects any kind of reality, but is nonetheless widely understood.

Still, it’s typically used more as an internal thing rather than an external thing.

Windows uses DPI terminology internally, but scaling factor externally. 100% is defined as 96dpi, so 120dpi is 125%, 200% is 192dpi, &c.

Browsers have devicePixelRatio as this same thing.

If you deal with floats as your basic unit of layout and such, I think a floating-point scaling factor is better for developer ergonomics than an integer or floating-point DPI.

@nmsmith
Copy link

nmsmith commented Jun 18, 2020

I still think it’s important to define a standard, even if it can’t be realised to full precision. A standard prevents the intent from drifting over time, e.g. we want to be sure that a GUI object doesn’t render twice as large (by human perspective) in 2030 as it did in 2020. Even if we just say “display points intend to closely match the CSS reference pixel in scale”.

As for the heritage of DPI, I’m personally not deeply familiar with the history of display scaling and thus I found references to “DPI” in the current Druid docs misleading. That’s just one data point from myself, but I imagine this will happen to other developers too.

@Zarenor
Copy link
Collaborator

Zarenor commented Jun 18, 2020

While I understand the idea of wanting that 'real' size information in theory, I don't think it's practical to assume we'll have even vaguely correct information in practice.

If we're lucky, we can read the EDID from the monitor and calculate the true DPI vs. logical DPI, but then we're going to behave differently from most other applications on the system if we use our real, calculated DPI.
And that would be in addition to the complexity we may already have in dealing with the possibility that 100% != 96dpi.

I'm open to the idea that there's a benefit here, but I'm having a hard time justifying the complexity (and added platform code to support fetching this information, when it's available, and failing gracefully when it isn't)

@xStrom
Copy link
Member Author

xStrom commented Jun 18, 2020

is it the visual angle of one pixel on a device with a pixel density of 96dpi and a distance from the reader of an arm’s length? If we don't have a definition, then a display point could be the size of a hippo

Whose arm though? A hippo's? That definition doesn't make any guarantees either.

We are not making any guarantees about physical space. We are abstracting platform behavior. That means that a single display point will be exactly as many platform pixels as the platform scaling methodology foresees.

Following the platform methodology will also enable the most frequent alignment to physical pixels. If we start doing precise physical space targeting then nothing will ever be pixel perfect.

Regarding DPI in the docs, I agree that it would be better to remove it so I opened #1042. Just surfacing a scaling factor better represents our intent.

@nmsmith
Copy link

nmsmith commented Jun 19, 2020

While I understand the idea of wanting that 'real' size information in theory, I don't think it's practical to assume we'll have even vaguely correct information in practice. If we're lucky, we can read the EDID from the monitor and calculate the true DPI [...]

Yeah, it does seem that this isn't practical. EDID is not available on all platforms, and on those where it is available, it isn't always correct. It ultimately doesn't seem worth the effort.

Following the platform methodology will also enable the most frequent alignment to physical pixels. If we start doing precise physical space targeting then nothing will ever be pixel perfect.

Yeah, this is fair.

Whose arm though? A hippo's? That definition doesn't make any guarantees either.

The next sentence defines a nominal arm's length as 28 inches, so CSS reference pixels do seem to be precisely-defined. From my perspective, it does appear that we could define display points to be the same as CSS reference pixels, because we can use the "standard viewing distance" of display devices as a fudge parameter to explain how a display point's physical size is determined. "Oh, your GUI content appears 20% smaller on display X than display Y? That's because display X has a smaller standard viewing distance." It's a fudged explanation, but it aligns well with cross-platform scaling behaviour, and it gives us a definition compatible with upcoming tech. People are going to be viewing 2D content on their AR glasses in 3-5 years time and when they do, we'll know how to set the scale!

Regarding DPI in the docs, I agree that it would be better to remove it so I opened #1042. Just surfacing a scaling factor better represents our intent.

Nice! I think this is a good simplification.

Copy link
Member

@cmyr cmyr left a comment

Choose a reason for hiding this comment

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

Thanks @xStrom, sorry for letting this sit for so long, I had aspirations to do some copy-editing but... clearly not very strongly-held aspirations. 😬

Copy link
Member

@cmyr cmyr left a comment

Choose a reason for hiding this comment

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

cleanup my bad newline 😞

CHANGELOG.md Outdated Show resolved Hide resolved
@cmyr cmyr added S-ready PR is ready to merge and removed S-needs-review waits for review labels Nov 16, 2020
@cmyr cmyr merged commit af52e13 into linebender:master Nov 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs concerns documentation S-ready PR is ready to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants