ValveSoftware / gamescope

SteamOS session compositing window manager
Other
3.09k stars 207 forks source link

Force Aspect Ratio in Fullscreen? #927

Open michaelneverwins opened 1 year ago

michaelneverwins commented 1 year ago

Let's say I have a 16:10 monitor (1920x1200) and a game that runs at a 16:10 resolution (320x200). This game could scale perfectly to fit my screen, and gamescope will gladly do it. But that's not actually what I want, because this game (like many 320x200 games) is actually meant to be displayed in 4:3. It turns out that my monitor's 1200-pixel height is perfect for scaling 320x200 to 4:3; I just don't want to use the monitor's entire width. Running such a game at 1600x1200 is ideal, as each of the game's pixels can scale exactly to 5x6, thus bringing the 320x200 graphics to a 4:3 aspect ratio without any scaling artifacts.

The use cases for having gamescope do this specific kind of aspect ratio correction are limited, because many such games are typically played in DOSBox or ScummVM which have their own aspect ratio correction settings. However, as an example, we can look at Icculus' Rise of the Triad for Linux. This source port has three resolution options — 320x200, 640x480, and 800x600 — but let's say I want the original 320x200 resolution scaled to 1600x1200.

Using gamescope's -S stretch option, I can stretch the nested 320x200 resolution to a 1600x1200 window, and the borderless window mode (-b) allows the game to use my monitor's entire 1200-pixel height without any space taken up by window decorations.

gamescope -w 320 -h 200 -W 1600 -H 1200 -S stretch -F nearest -b -- rott resolution 320x200

But maybe I don't want to see my desktop on the sides, and would rather have the game run in pillarboxed fullscreen.

So my first instinct is to set gamescope to fullscreen mode (-f):

gamescope -w 320 -h 200 -W 1600 -H 1200 -S stretch -F nearest -f -- rott resolution 320x200

Unfortunately, the game is then scaled to the entire 1920x1200 display, whereas I would prefer it to be pillarboxed to the 1600x1200 output resolution specified. It seems that the behavior of -f is to use the entire display as the output resolution regardless of -W and -H, and thus -S stretch with -f will always stretch to fill the screen rather than stretching to the given output resolution.

Is there a way to have gamescope stretch 320x200 to pillarboxed 1600x1200 in fullscreen mode on a 1920x1200 display? If not, would implementing such a feature be possible? In generalized terms, this would mean fullscreen mode being able to support an arbitrary aspect ratio which is neither that of the game window nor that of the actual screen.

Amusingly, I can get what I want by wrapping gamescope inside of gamescope:

gamescope -w 1600 -h 1200 -f -- gamescope -w 320 -h 200 -W 1600 -H 1200 -S stretch -F nearest -- rott resolution 320x200

However, that doesn't seem like the right way to do it.

Full disclosure: I've been playing around with an unsupported build of gamescope (from here) due to Linux Mint 21.2 not having the dependencies required to build from this repo's master branch. However, I assume this doesn't matter unless what I'm seeing is actually a bug. I'm just here to request a feature or to find out whether such a feature is already implemented in some non-obvious way. If it turns out that gamescope can already do exactly what I want using the gamescope -w 320 -h 200 -W 1600 -H 1200 -S stretch -F nearest -f command I've already tried, and that the problem is actually my unsupported version of it, then I'll go away.

AlexFolland commented 4 months ago

I've encountered this issue as well today, also on a 1920 by 1200 display. I am trying to set up a system using dosbox in gamescope and see the output at a pillarboxed fullscreen 4:3 aspect ratio on my 8:5 display. The following is the command I've tried, with dosbox' output variable set in dosbox.conf to opengl. Zink is used to force translation to Vulkan, circumventing Nvidia's bad OpenGL driver.

__GLX_VENDOR_LIBRARY_NAME=mesa MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink gamescope --fullscreen --nested-width 320 --nested-height 200 --output-width 1600 --output-height 1200 --scaler stretch --filter pixel -- dosbox

The --output-width 1600 argument is ignored.

Everything otherwise works in windowed mode with --output-width 800 --output-height 600, but I want it to be fullscreen and this bug is preventing it.

michaelneverwins commented 2 months ago

I am trying to set up a system using dosbox in gamescope and see the output at a pillarboxed fullscreen 4:3 aspect ratio on my 8:5 display.

Last time I used DOSBox for a 320x200 game — well, actually, it was DOSBox Staging — I was able to get it to scale to 1600x1200 on my 1920x1200 display just by using built-in settings, i.e. without gamescope, which is why I didn't use it as an example use case. I didn't back up my configuration file before recently doing a fresh install of Linux Mint 22, so I don't remember exactly what the settings were, but you might have better luck just trying to enable DOSBox's aspect ratio correction. (Or, if you need to run it inside of gamescope for other reasons, maybe give it --nested-width 1600 --nested-height 1200 so that DOSBox has room to "stretch" the image into the space gamescope gives it, and then remove gamescope's --scaler stretch.)

By the way, it has come to my attention that Icculus' Rise of the Triad port may also be a bad example use case, because I'm now seeing that its resolution 320x200 mode is correcting to 4:3 without gamescope's help. I'm quite sure this wasn't the case before, and, as far as I know, I didn't do anything except for upgrading to Linux Mint 22 and then installing rott again. I don't think the source port itself received any updates*, so I don't know what changed. Maybe something in SDL changed, but frankly I have no idea.

* Edit: I might be wrong about the source port itself not having been updated, because APT shows the version as 20230810-1 (so it's actually dated a couple of days before this issue was opened, but I don't think a stable distro like Linux Mint 21.2 would have had such a recent update already). I also notice that the manual page lists only 320x200 and 640x480 as valid resolutions whereas in the original post I had also mentioned an 800x600 option, although I have no idea why one would have been removed.

In any case, running

rott fullscreen resolution 320x200

now fills the 1600x1200 area of my 1920x1200 screen and seems to be giving me perfectly nice scaling with 5x6 pixels. It apparently does this correction by decreasing the width rather than by increasing the height, so

rott window resolution 320x200

fills a 266x200 portion of a 320x200 window by default (i.e. before window resizing), and thus running

gamescope -w 320 -h 200 -W 1600 -H 1200 -S stretch -F nearest -f -- rott resolution 320x200

does fill a 4:3 area of my screen but the scaling looks bad. Basically, there's no reason to use gamescope for this now, and I feel silly.

But despite the original post's use case now being possibly invalid, the main point was gamescope apparently lacking the ability to run in fullscreen while stretching to an aspect ratio other than that of the physical screen, which might still be useful in some cases.

AlexFolland commented 2 months ago

Dosbox doesn't have an overscan scaler which uses the average color between the neighboring pixels when scaling, which is what the --filter pixel part of the gamescope command does. Gamescope should be able to wrangle any output and display it exactly how I want, and this bug prevents that right now.

The key point of this bug is that the --output-width 1600 gamescope argument is ignored. Fix that so that gamescope interprets that argument correctly in fullscreen and the bug will be fixed.

misyltoad commented 2 months ago

Adding support for an aspect-ratio scaler should be very easy. It would just need some logic in calc_scale_factor_scaler.

misyltoad commented 2 months ago

Output Width/Height is more meant for DRM backends or the default width/height. It gets updated with the window size.

misyltoad commented 2 months ago

Also, if you wanted fixed width/height, I think that'd also be best for calc_scale_factor_scaler and another scale mode.

AlexFolland commented 2 months ago

It is not ignored in windowed mode, so the issue is only that it is ignored in fullscreen mode. It should just letterbox with black any unused pixels in the fullscreen output.

misyltoad commented 2 months ago

Not sure what you mean, as when you resize the window it gets updated. It just defines the default size of the output window.

AlexFolland commented 2 months ago

I mean that the image is correctly squished to the target output width and output height without clamping to a 1:1 square pixel shape when in windowed mode (without the --fullscreen argument), but the pixel shape seems to be forced to 1:1 (square pixels, ignoring the --output-width argument) when in fullscreen (with the --fullscreen argument).

I mean if I use --nested-width 320 --nested-height 200 --output-width 1600 --output-height 1200 in windowed mode, I get the intended 1600 by 1200 surface drawn in a window (which doesn't fit on the screen due to window borders and doesn't hide other screen elements because it's in windowed mode), but if I use --fullscreen --nested-width 320 --nested-height 200 --output-width 1600 --output-height 1200 in fullscreen mode, I get a 1920 by 1200 surface which is filled entirely by the game's output; not letterboxed with the intended 4:3 aspect ratio, but a full fill of the 8:5 aspect ratio of 1920 by 1200 instead of the intended 4:3 aspect ratio of 1600 by 1200.

Not sure what you mean, as when you resize the window it gets updated. It just defines the default size of the output window.

Edit: After testing resizing in windowed mode, I see what you mean by this now. This also looks like a bug, since gamescope doesn't respect and maintain the output aspect ratio specified by the --output-width and --output-height arguments when the window is resized to arbitrary sizes.