mupen64plus-libretro-nx icon indicating copy to clipboard operation
mupen64plus-libretro-nx copied to clipboard

Native resolution option

Open Bezier89 opened this issue 5 years ago • 68 comments

First off, awesome work! This is a big improvement over the previous Mupen64Plus core. If it matters, I'm using the build from https://m4xw.net/nextcloud/index.php/s/ASMiAmQBPnP8D3w

Gauntlet Legends boots up and plays mostly ok. However, the text is very blurry (even unreadable in some cases). I compared it to Angrylion which looks perfect (alas, it's too slow on my machine). Comparison below, same shader for both. Yes they're taken with my phone :) was faster than getting a proper screenshot.

Mupen64Plus Next (all default settings): IMG_20190320_201709

Parallel N64 (with Angrylion): IMG_20190320_200719

I eventually determined this is because the resolution is set to 320x240. However, setting the resolution to the next level up, 640x480, isn't quite right either. It appears this game runs at 640x240 (at least, that what is with Angylion, and that looks right to me). The vertical resolution does matter since it greatly affects the look of scanlines from the shader. Also according to https://nintendo.fandom.com/wiki/Nintendo_64_Expansion_Pak, it would appear there are a wide variety of resolutions between 320x240 and 640x480 that are used. Ideally there should be a "native resolution" option in addition to the fixed resolution options. However, if it's easier to implement, a reasonable partial solution would be a "320x240 with high-res" (maybe you could come up with a better name) option. That would be 320x240 for most games, but would switch to 640x480 for games that use any higher resolution.

Bezier89 avatar Mar 21 '19 01:03 Bezier89

Can you check the GLideN64 branch?

m4xw avatar Mar 21 '19 10:03 m4xw

There is also config.frameBufferEmulation.nativeResFactor, I don't expose that tho.

m4xw avatar Mar 21 '19 11:03 m4xw

@m4xw Do you mean check https://github.com/libretro/mupen64plus-libretro-nx/tree/GLideN64? Isn't that what https://m4xw.net/nextcloud/index.php/s/ASMiAmQBPnP8D3w is built from?

I briefly searched the code for "nativeResFactor". Base off this snippet, it sounds like setting nativeResFactor to 1 might give me what I want, but I haven't tested that.

Also, some related discussions here:

https://github.com/libretro/parallel-n64/issues/403 https://forums.libretro.com/t/automatically-select-native-resolution-for-n64-games/2073

Just for some additional justification besides the "purist" perspective, another reason such an option would be preferable over simply always using 640x480 is that some games have graphical artifacts when rendered at 640x480 (e.g. Bomberman Hero).

Bezier89 avatar Mar 21 '19 12:03 Bezier89

Do you mean check https://github.com/libretro/mupen64plus-libretro-nx/tree/GLideN64? Isn't that what https://m4xw.net/nextcloud/index.php/s/ASMiAmQBPnP8D3w is built from?

Yes

m4xw avatar Mar 21 '19 12:03 m4xw

That's the build I'm using.

Bezier89 avatar Mar 21 '19 12:03 Bezier89

You can try just hard-coding GLideN64\src\Config.cpp line 64 to 1.

m4xw avatar Mar 21 '19 12:03 m4xw

Made that change. Managed to build successfully (attached). Will test out tonight.

Edit: and a build with nativeResFactor hard-coded to 2

Bezier89 avatar Mar 21 '19 18:03 Bezier89

@m4xw I believe I've determined what the nativeResFactor setting does. When it's set, Mupen64Plus renders to an internal framebuffer that is the set multiple of the game's native resolution. Bomberman Hero is a good way to verify this, since it has visual artifacts at 2x native resolution that do not show up at 1x native resolution.

Regardless of nativeResFactor, the final output resolution resolution is always the resolution in the settings. So somewhere along the way it gets scaled (looks like biliear) to that resolution before being handed off to Retroarch. If you were just going to use simple bilinear filtering to bring it up to your display resolution this intermediate scaling wouldn't really matter, but with the way Retroarch's shaders work it's best if the input is at native resolution.

I've found a reasonable compromise to be have nativeResFactor at 1, resolution at 640x480, and a 2-stage shader. The first stage scales the image down to 640x240, the second stage is the shader I actually want to apply. This looks pretty decent for most games, although isn't ideal for games that had > 240 vertical resolution. This could be done more simply by 1) exposing the nativeResFactor option (not sure you need to expose an integer, a true/false "Render at native resolution" option seems sufficient) and 2) adding a 640x240 resolution option. Even better though, would be to find the code that scales from the internal framebuffer to the resolution in the settings and disable that when nativeResFactor is set.

Bezier89 avatar Mar 22 '19 01:03 Bezier89

Looking through the code a bit, I think libretro is what's responsible for scaling from the framebuffer resolution to the resolution in the settings, and I think that's controlled here. Instead, in native resolution mode you would want to set it based on VI.width/VI.height. There's also a whole lot going on in this codebase and I've only just started looking at it, so I could be off base here.

Bezier89 avatar Mar 22 '19 02:03 Bezier89

Thanks I will investigate it.

m4xw avatar Mar 22 '19 10:03 m4xw

Based on the threads here and here, assuming what they say is accurate, then regardless of whatever resolution the internal framebuffer is (which is often 320x240, but can be a variety of resolutions, and can even change midgame) the N64 always scales the output to either 640x240p or 640x480i. Angylion follows this approach - every screenshot I took with it was either 640x240 or 640x480, and the 640x480 screenshots were clearly interlaced (I guess angrylion being a low-level plugin actually implements interlaced rendering).

An "output directly at framebuffer resolution" option would be interesting, although not strictly faithful to the N64, and harder to implement. I think the approach I hacked together to simulate 640x240 is probably pretty close to the right approach. I suppose the question is mostly how to present these options to the user. I have a few proposals:

  1. A true/false "Render at native resolution" option
  2. Replace the "4:3 Resolution" and "16:9 Resolution" options with independent "Horizontal Resolution" and "Vertical Resolution" options. Default to 640 horizontal and 240 vertical. The aspect ratio is still controlled by the "Aspect Ratio" option.
  3. Not as important, but as a "nice to have", maybe an option to double the vertical resolution if the game is in interlaced mode. This only really matters if you have a low vertical resolution, so maybe one of the options under "Vertical Resolution" could special case this. Something like "240p/480i" which sets vertical resolution to 240 if the N64 requests progressive output and 480 if it requests interlaced output.

Implementing the third of those is a bit beyond me at this point, but I could implement the first two if you're interested. Might be a couple weeks before I have enough free time to get around to it, though.

Bezier89 avatar Mar 22 '19 15:03 Bezier89

libretro supports rendering to a max_width and max_height. there is a "base_width, base_height" which is a floor() option.

libretro can render to any resolution in between. Its just a matter of rendering to the render target at that resolution which is in the video_refresh callback.

ghost avatar Mar 22 '19 22:03 ghost

Just to add on to this. M64p automatically selects the native resolution for every game and scales it from there. Using an expansion pack will also change the internal emulated resolution to what is should apporiatly be. It would be great for a feature where we don’t have to select a games resolution and it just had an “auto” setting where it picks the correct one based on the game and expansion pack settings.

HappehLemons avatar May 18 '19 00:05 HappehLemons

@m4xw Quick question: I saw that you're claiming the bounty, but the "mupen_next" branch is still old. Is the buildbot now pointing to the "GLideN64" branch? And if so, should that be updated to the default?

I ask because I may take a look at this later, and want to make sure I'm working off the right branch.

Bezier89 avatar May 21 '19 00:05 Bezier89

@Bezier89 use the GLideN64 branch, it will be merged after I figured how I want to progress with multi-plugin-support. fwiw I changed the default branch or the time being

m4xw avatar May 21 '19 08:05 m4xw

I recently talked about the poor image quality in some N64 games.

https://forums.libretro.com/t/n64-poor-image-quality/22857

Very good to know that will be implemented a native resolution option in Mupen64Plus Next core.

Thanks all to the work and dedication!

S2

lfanog avatar Jun 15 '19 17:06 lfanog

Thanks for the work. This explains why many games look blurry. Even with upscale filters

Papermanzero avatar Jul 20 '19 16:07 Papermanzero

@Papermanzero you want to close the other issue then?

m4xw avatar Jul 20 '19 16:07 m4xw

In general there are Independent issues: This one is native resolution, the other is texture filtering/scaling. Both lead to a blurry image. I compared the image quality with beetle psx and I was surprised that the mupen core display many things like fonts so blurry and unsharp compared to psx games. I think the native resolution is the main issue which leads to this behavior.

therefore i will close the other issue, because @gonetz has to implement the sprite/texture filtering or scaling feature in gliden64.

Papermanzero avatar Jul 20 '19 17:07 Papermanzero

@bezier89 - Can you share what shader you used for scaling as I'd like to do something similar to you?

cobhc2019 avatar Jul 24 '19 19:07 cobhc2019

@cobhc2019 I use crt-lottes-fast with the following settings:

Mask Type                  3.00
Mask Intensity             0.60
Scanline Intensity         0.40
Sharpness                  2.50
Curvature                  0.00
Triniton-style Curvature   0.00
Corner Round               0.00
CRT Gamma                  2.40

Also, if anyone is interested on working on this issue, feel free to take it. Just had a kid so we've been a bit busy :)

Bezier89 avatar Jul 25 '19 10:07 Bezier89

@bezier89 Is that for the scaling as well? I was more interested in what you were doing to scale 640x480 down to 640x240.

cobhc2019 avatar Jul 25 '19 11:07 cobhc2019

@cobhc2019 Ah, that. I just apply a stock linear filter first to scale it down. See attached file for examples (glsl and slang). It downscales both axis, but change scale_x0 to 1.0 if you want to only downscale the vertical (y) axis.

Bezier89 avatar Jul 25 '19 11:07 Bezier89

Pay close attention to the edge... gonetz/GLideN64#1981

Jj0YzL5nvJ avatar Aug 11 '19 19:08 Jj0YzL5nvJ

Any update on that one?

Papermanzero avatar Sep 14 '19 12:09 Papermanzero

@Papermanzero I might look at that before christmas

m4xw avatar Nov 27 '19 14:11 m4xw

@Bezier89 wanna give this a try? Keep in mind it uses different filtering so its gonna be a bit more blurry anyway. Make sure you set 640x480 4:3 for testing, this also forces nativeResFactor. mupen64plus_next_libretro.zip

m4xw avatar Nov 29 '19 15:11 m4xw

hah, parallel's AL def renders at higher resolutions than it should for real native res...

m4xw avatar Nov 29 '19 16:11 m4xw

@m4xw Nice work. Has the filtering logic changed in this core recently? Even at 320x240, Gauntlet Legends is much more readable than it used to be.

Old build (from when issue was created): 320x240 Gauntlet Legends (USA) z64-191130-093208

640x480 Gauntlet Legends (USA) z64-191130-093912

Latest official build (as of 11/30/2019): 320x240 Gauntlet Legends (USA) z64-191130-094238

640x480 Gauntlet Legends (USA) z64-191130-094320

Build from your comment: 640x480 (although 320x240 looks identical as far as I can tell): Gauntlet Legends (USA) z64-191130-094446

Even with the improved filtering, this seems like a worthwhile feature. The screenshot from your build appears to have slightly less blurry text compared to 320x240 from the latest official build. Also I can confirm that games that have artifacts at 640x480, such as Bomberman Hero, do not exhibit said artifacts.

Bezier89 avatar Nov 30 '19 14:11 Bezier89

@Bezier89 can u give me some close up shots like the first post? That build still doesnt have the nearest neighbours scaling i want Heres another example (left is my build, right is current) grafik There also has been a regression upstream, there is no longer true support for rendering lower than real hw would have, so I have to force nativeResFactor = 1 for lowest configuration (still need to create a issue on Gliden with my findings.. have been procrastinating on that) The build I gave you sets the Resolution u set as max but it will always display the resolution the N64 would render and pretty much every funky number inbetween for each VI. I will write some more details tomorrow or monday, got to go now. (Also yes theres a new hybrid filter for some textures on upstream GLN64)

m4xw avatar Nov 30 '19 18:11 m4xw