Plasma icon indicating copy to clipboard operation
Plasma copied to clipboard

Adding cursor scale

Open colincornaby opened this issue 2 years ago • 7 comments

Cursor scale corrects corrects the size of the cursor on Retina displays.

Proposing this change for supporting hi DPI displays. On Mac, this is tied to the Retina display scale. It corrects for the cursor being way too small as the resolution increases. On a Retina display, this will draw the cursor at 2x. While on a non Retina display the cursor will remain 1x.

Cursor scale is an independent property because a lot of things touch the cursor frame. This allows the scale to stay constant even if something else does a resolution change.

On Windows - this could be tied to display scale. Proposing this change for mainline, and am using it in the Mac branch.

colincornaby avatar Jun 18 '22 03:06 colincornaby

Thinking this one through a bit more. The cursor size should almost stay constant even as the resolution changes. If I lower the resolution, the cursor shouldn't get bigger.

Plasma's cursor behavior seems like a holdover from when the actual resolution of the display changed. These days, in Metal I'm just changing the resolution of the main render pass buffer, but not actually the display. So the cursor surface can stay constant even if the render pass output resolution changes.

The only problem is Plasma tries to be helpful and always keep the mouse display resolution in sync with the actual output resolution, which is why I had to add display scale as a separate property. So if I set the output resolution to 1080p on a 1440p display, the cursor is going to get bigger even if the window is still a 1440p window.

colincornaby avatar Jun 18 '22 04:06 colincornaby

My opinion as the one who wrote the original cursor drawing code (replacing Cyan’s broken one) is that the cursor should not be of a constant size relative to the screen size, but align to the output pixels, so that it is not blurred. That was the problem with Cyan’s original code, which I fixed – the cursor was scaled in a weird way and not aligned to the pixel grid, making it very blurry.

Extended to high-resolution displays, that would mean drawing at 1:1 on a 1x display, 2:1 on a 2x display etc., which if I understand correctly matches your original idea. In other words, the user decides how large physically the cursor should be by their desktop display scaling setting. Ideally, there should also be 2x bitmaps so that we don’t have to scale up the 1x ones, or even better the bitmaps would be rendered at runtime from the vector sources (which would allow arbitrary sizes with minimal blurring).

Of course, if the output of the game is then scaled again to a display with a different pixel size, the blurring argument becomes somewhat moot. It’s probably also less of an issue now with today’s relatively high-resolution displays (even those run at 1x) compared to when we had 19" 1024×768.

cwalther avatar Jun 18 '22 07:06 cwalther

One issue is with LCDs the output pixel size is constant. LCDs can only render at the native panel resolution or scale. To actually align the cursor with the pixel grid, I would always have to draw the cursor at native panel output resolution. Which is possible and can be done. But that would actually have the affect of locking the cursor to a constant size.

A lot of modern games do detach the cursor from the render resolution. So the game is rendered at whatever resolution the user has selected for performance. But UI like the cursor is always drawn in a separate pass at panel resolution.

That also prevents weird issues like the user dropping in and out of windowed mode. When they drop to windowed mode and the output resolution becomes a lot smaller, you wouldn't want the cursor to suddenly become a lot smaller. Ideally the cursor should stay the same size between windowed mode and full screen mode.

Same tradeoff is the user cuts down the resolution to a scaled resolution for performance reasons. They might want to make the gamer render at a lower res to maintain frame rate. But that also doesn't mean the cursor should necessarily grow larger just because the game is rendering at a lower res. If I'm on a 4k screen but rendering at 1080p for performance, I don't necessarily want the cursor to double in size.

colincornaby avatar Jun 18 '22 08:06 colincornaby

A lot of modern games do detach the cursor from the render resolution. So the game is rendered at whatever resolution the user has selected for performance. But UI like the cursor is always drawn in a separate pass at panel resolution.

That would of course be the best thing to do. No idea how easy it would be in Plasma, I’ve been away from the code for a long time (and have never even looked at the Mac work being done, even though macOS is my preferred OS).

I guess what I was trying to say was: If a user runs the game at a different resolution than their desktop and/or display panel, all bets are off, and the blurry cursor is their own fault. But a user who takes care to match the resolutions of the game, desktop, and physical display should still be able to get a crisp, pixel-perfect cursor. To me, sharpness is more important than exact size. I’m OK with having the size quantized to a relatively coarse discrete scale like 1x, 2x, … in exchange for avoiding blurring.

cwalther avatar Jun 18 '22 08:06 cwalther

To be honest - I'm not sure how to handle resolutions on the Mac. I'll do a small info dump.

Modern macOS games never change the resolution of the display. Actually changing the display resolution is discouraged. It also prevents issues if the system needs to display a notification, or the user command tabs to a different app. That means Plasma on Mac will always render at native display resolution, and it's Plasmas responsibility to draw at a lower resolution manually and then scale the output up to panel resolution.

That gives me some flexibility. Because there will always be a frame buffer somewhere at native resolution, I can draw the 3D content at one resolution, and then all plates at native resolution.

The new Myst remaster actually does this. Screen Shot 2022-06-18 at 2 33 53 PM

Window resolution controls the output buffer resolution, while resolution scale 3D allows the 3D content to render at a lower resolution for performance. Myst actually locks the output buffer to panel resolution. (It's also locking the 3D scale, not sure why.)

If I switch it to normal fullscreen instead of windowed fullscreen, things get a little wonky. It tries to emulate display mode behavior, but the display modes macOS returns to it are wrong. So it won't offer native panel resolution at all. The best it will offer me is 2560x1440.

Screen Shot 2022-06-18 at 2 44 23 PM

World of Warcraft also has a similar control. Their display modes do work - but again it's just best to change the resolution scale and not even bother with display modes. Resolution scale changes the scale the 3D content is rendered at while leaving 2D things - like the cursor, at window res.

I'm not quite sure what the right answer is for how Uru should handle display modes on Mac. I'm worried about laptop users who change between internal and external displays (either while Uru is running or between sessions) and I'm not sure how Uru handles display modes changing today. 3D scale could carry between displays, while display modes won't.

Scaled behavior would be nice for lower end Intel machines. The cursor could stay crisp and at panel res, while the user makes a small tradeoff in 3D quality by lowering the 3D scale.

I also don't want to do anything disruptive to the Windows client. And adding a 3D scale setting to Plasma risks causing issues for Windows.

If I don't render the cursor at panel res, weird things start happening. If I render on a 4k panel at 1080p, the user interface scale is still 2x for the Uru windows. So I'll take the cursor at 1080p size, and then double it again in size.

So I don't really have a clear answer right now on how macOS should handle resolutions. It's very possible to always render the cursor at panel res - adjusting for UI scale. But the entire concept of display modes and how the user is offered different resolutions is a bit of mystery to me still.

colincornaby avatar Jun 18 '22 22:06 colincornaby

Ok - bringing this one back out of draft again. Essentially the core feature of this PR is to address when the window is a different size than the underlying framebuffer. The core example of this is still macOS. On a 4k display, the "window" and cursor is going to be 1920x1080. But the underlying framebuffer will be 3840x2060. To better match the window server, the cursor size should also be scaled up to exist in window manager co-ordinates instead of framebuffer co-ordinates.

There are other iterations of this problem. For example, framebuffer resolution might be reduced to maintain performance, but window server resolution of the game window stays unchanged. Windows used to address this by changing the display mode of the actual display - forcing the window manager to the same resolution. That's not how modern Mac (or Windows) applications work.

Along with this PR comes an initial round of text fixes for the cursor. Offsets for things like player names from the cursor were hardcoded. This calculates offsets on the fly based on the cursor size.

colincornaby avatar Aug 02 '22 05:08 colincornaby

This looks sensible to me. I think I would like to see a use case of it in the game itself before we merge it though, just so we have an active use case. I think it should be trivial to hook this up to the Windows DPI awareness stuff - I can probably glance at that this weekend if you want.

Hoikas avatar Aug 03 '22 23:08 Hoikas

I have a better set of changes for this - closing this pull request. New one will be opened.

colincornaby avatar Dec 05 '22 04:12 colincornaby