[haiku-development] Re: HiDPI strategies, current and future

  • From: "Adrien Destugues" <pulkomandy@xxxxxxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Tue, 31 Aug 2021 17:09:20 +0000

I am trying to pave the way a little bit so that we do not have to
re-engineer HiDPI when we do get multiple screens (which I think is
actually not too far off, as intel_extreme and radeon_hd support it
internally, and test_app_server supports it too, so it is just a
question of making everything meet in the middle; for the first cut,
anyway.) The current model is not at all suited for multiple screens,
so, this proposal attempts to rectify that before we get too far into
things (e.g. Decorators are not yet adjusted at all.)

The intel driver does not really support it yet. Otherwise I would already
be on my way to making the app_server parts work.


Second, I already mentionned that in the linked discussion I think, your
proposal dives directly into technical and developer-oriented things. But
the main problem here is user centric, and that's something we should keep
in mind.

I think the user-centric problem is the easiest one to solve, hence
why I am primarily touching on technical matters here. But yes, we do
need to keep this in mind.

But it isn't solved, since we end up with two independant settings.
This is not only annoying for users, it also makes it difficult for
developers to make sure their application work in all cases.

Currently, you basically need to test 10pt font, 24pt font, and maybe something 
in
between, and you know if your UI works at these size, it will work all the time.

But if there are two separate settings, now you need to test at least 4 cases:
- Low density + small font
- Low density + large font
- High density + small font
- High density + large font

And probably some things in the middle. I think this is going to create problems
where some apps don't work with certain settings. Even if the layout kit does 
quite
a good job at setting size constraints, for complex apps this will always be a 
problem.

It may be slightly less than optimal, I suppose, yes. But it does have
the advantage that some metrics can now be at least slightly decoupled
from the font size, as some users seem to want, at least implicitly. I
don't know if that's really an advantage in the long term, but I think
the disadvantage of having two places to set things is outweighed by
the overall advantages.

Well, I don't really agree. Two different settings make things complicated
and confusing for both users and developers.

You get it from BFont, which ultimately gets it from BScreen. The idea
is that individual views or windows could have scaling "disabled" by
just setting a BFont with density 1, so all actual drawing logic
should still use the BView's BFont density, not BScreen's density
values.

We'll have to see how this works in practise. My worry here is that the
"density" is an arbitrary unit and as such feels a bit abstract to me,
and as a result, hard to reason with.

I guess what would work best in that aspect is workign either with pixels,
or some well-defined unit (typographic points, millimeters, inches,
"device independant pixels", roughly by order of preference for me). I
find it easier to work with two well defined coordinate systems than work
with a single system (pixels) and a scaling factor (density).

It probably won't matter this much, anyway: with the layout kit, application
writers will rarely have to deal with these things anyway.

The other worry is getting the info from BFont. This means the BFont object
must remember which screen it is attached to.

So if you do something like this:

BFont myFont;
// configure the font here...

window1->view->SetFont(myFont);
window2->view->SetFont(myFont);

Now your two views actually have different fonts, possibly neither of which
is the one you defined (because they both have non-default scaling). This
ends up being a bit confusing.

So I think I would deprecate the StringWidth and other related methods in BFont,
and keep only the BView version. Or at least make them work at some default
scale only. This would force developers to always do things in the context of
a given view, which will be in sync with a given screen (or other context, for
example in the case of printing).


Also, what happens when a window is shown in
two screens at the same time? (either because you're using "clone" mode on
two displays with different resolutions, or because you're moving a window
from one display to another and it's somewhere in the middle). I currently
don't understand how this will work with layout, Invalidate and Draw calls
(since all of these work in pixels).

Yes, this is a problem no matter how you look at it. I think my
proposal neither helps nor hurts with any kind of solutions here, it
is just orthogonal. So unless I have missed something, I think this is
a problem for another day.

As you said, if we are redesigning the way we scale the UI, let's try to think
about all the cases, so we don't have to redesign it again later. Or at least,
know the limitations in our design choice.


I think the window will be in some kind
of "split brain" state and have two halves drawn completely separately, with
completely different layouts, which seems complicated to do; or maybe it 
would
keep the scale of one display and draw everything using that, which will be
noticeable by the users (the window suddenly scales up or down when you move
it from one screen to another).

The latter approach, or a hybrid of the latter approach where bitmap
scaling is used for the part on the other screen, would probably be
best. (MS Windows does something similar to this.)

The way it's done in Windows doesn't really look great with the bitmap scaling.
I guess we could try fun things like progressively changing the scaling factor
as the window gradually moves from one screen to the other, providing a smooth
transition. Not sure if the lots of redraws needed would make this work so well,
however. But it sure would be nice to show if we can get it working.


Third, you start by stating a problem which is that a lot of things don't
scale linearly (in particular at small font sizes), then go on with a
proposal that does not tackle this problem. We will still have to have
a min() call to have a reasonable border around text at small font sizes.

Not necessarily; you could now just use the font's density directly
instead of any other values computed from the font metrics. Users
could still set a density of 75% or something like that, but it would
have to be with the understanding that the whole UI is going to be
affected there, whereas font sizes < 12 may not scale down the rest of
the UI so long as density is still at 1, if that makes sense.

Probably we need a max() too at larger font sizes.

Why would that be? There are some extremely dense screens around these
days, why would we want to arbitrarily limit how large the UI can
become?

I think your approach of the scaling factor blindly affecting everything
proprotionally is not going to work so well. If I understand correctly,
the font size could not be adjusted per-display in this scenario.

If you think about extreme cases, say, a 320x240 display, you really don't
want to waste any pixels there. Yet, you need a rather large font, because
it's simply not possible to draw very small text (there just aren't enough
pixels). So in this case you will want a rather large font, but very small
margins. On the other hand, if you have a very high resolution display, and
good eyesight, you may want a small font to fit more text. But you may still
want to increase the margin around buttons a bit, so you can easily target
buttons with your mouse.

Of course, this is an extreme case, but I think this effect can be visible
if you have a low end laptop (let's say 12" 1366x768 display) and a retina
display (let's say a 24" or larger one) connected to it. If I had a setup
like that, I would want smaller fonts on the retina display, and somewhat
larger fonts (so they remain readable with lower resolution), but smaller
margins (to not waste any space), on the laptop.

In that situation, an approach where the only thing I can adjust between
the two displays is a linear scaling factor that affects everything, is
not going to work.

That's what I'm referring to with the max() call above. I think one way
to handle this is that some UI elements (mainly margins between controls,
or between control edge and text) would have a minimal and maximal size,
or at least not scale as much as the text itself when changing the scaling.

I don't know if we can find a good way to compute this, maybe it's too hard
to do and we will just have to decide which kind of display we design our
UI for, knowing that the rendering on smaller or higher resolution displays
will not be as perfect as it could be.

Having two separate settings controllable by the user may also be a way to
achieve that, but I think it will not work so well with the settings being
"font size" and "display density". However, I currently don't have a retina
display, so, it's something I can't really experiment with, even if I had
dual screen support. So I may be overengineering things here and maybe we
could get things to look ok. Would be nice to do some experiments and see
where we are going, still.

-- 
Adrien.


Other related posts: