libretro / mupen64plus-libretro-nx

Improved mupen64plus libretro core reimplementation
GNU General Public License v2.0
229 stars 114 forks source link

Native resolution option #37

Open Bezier89 opened 5 years ago

Bezier89 commented 5 years ago

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.

m4xw commented 5 years ago

Can you check the GLideN64 branch?

m4xw commented 5 years ago

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

Bezier89 commented 5 years ago

@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).

m4xw commented 5 years ago

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

Bezier89 commented 5 years ago

That's the build I'm using.

m4xw commented 5 years ago

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

Bezier89 commented 5 years ago

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

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

Bezier89 commented 5 years ago

@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 commented 5 years ago

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.

m4xw commented 5 years ago

Thanks I will investigate it.

Bezier89 commented 5 years ago

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.

ghost commented 5 years ago

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.

HappehLemons commented 5 years ago

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.

Bezier89 commented 5 years ago

@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.

m4xw commented 5 years ago

@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

lfanog commented 5 years ago

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

Papermanzero commented 5 years ago

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

m4xw commented 5 years ago

@Papermanzero you want to close the other issue then?

Papermanzero commented 5 years ago

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.

cobhc2019 commented 5 years ago

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

Bezier89 commented 5 years ago

@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 :)

cobhc2019 commented 5 years ago

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

Bezier89 commented 5 years ago

@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.

Jj0YzL5nvJ commented 5 years ago

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

Papermanzero commented 5 years ago

Any update on that one?

m4xw commented 4 years ago

@Papermanzero I might look at that before christmas

m4xw commented 4 years ago

@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 commented 4 years ago

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

Bezier89 commented 4 years ago

@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.

m4xw commented 4 years ago

@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)

Bezier89 commented 4 years ago

@m4xw Any particular games/examples you want screenshots of? I can get more this weekend if you want.

Immersion95 commented 4 years ago

It would be perfect if it's officially added :).

This option is essential for me !

Thanks a lot !

m4xw commented 4 years ago

I will get back to it eventually... I got too many branches going on,lol.

Immersion95 commented 4 years ago

I will get back to it eventually... I got too many branches going on,lol.

Thanks a lot for all of your work !

Can this option be also added to Parallel ?

lfanog commented 4 years ago

Hi, @m4xw !

I played the World Cup 98 and the texts looks better. Did you make changes?

m4xw commented 4 years ago

With the linked build? Yes, but only at native resolution!

lfanog commented 4 years ago

With the linked build? Yes, but only at native resolution!

No. The last Mupen64Plus-Next (1.039b555e).

Before

World Cup 98 (USA) (En,Fr,De,Es,It,Nl,Sv,Da)-190614-235947

Now

World Cup 98 (USA) (En,Fr,De,Es,It,Nl,Sv,Da)-200201-213336

With CRT-Composite shader

World Cup 98

Video Aspect Ratio: Custom Custom Aspect Ratio Width: 1600 Custom Aspect Ratio Height: 1200 Integer Scale: OFF

Shader crt-guest-dr-venom-ntsc-composite-stock

Core options 4:3 Resolution: 320x240 Bilinear filtering mode: 3point MSAA level: 8 Native res. 2D texrects: Optimized

m4xw commented 4 years ago

That looks like you used a build when rendering at 320x240 was still supported in gliden. It currently no longer works and uses nativeresfactor (<640x480) Its better that way anyway but it has some extra impact for low low low perf devices. The linked build improves that even more but i need to rebase it. Core options will get some love in the future too... it's currently a bit messy.

lfanog commented 4 years ago

I will look forward to your new modifications to the core.

Thanks!

Papermanzero commented 4 years ago

Native 640x480 would be really nice. But I think there is still a blur which you can recognize in games like yoshis story.

m4xw commented 4 years ago

@Papermanzero you want to make sure you dont have bilinear on in RA's video settings.

Papermanzero commented 4 years ago

@m4xw For sure. I tried different combinations of settings. But thanks for the hint. 😊 If i find time i will compare it with angrylion and post some screenies.

m4xw commented 4 years ago

@Papermanzero actually I just reminded myself -> yea that was todo, I scaled the pics manually with nearest since thats the final output i expect when its done.

dankcushions commented 4 years ago

hi @m4xw, we (RetroPie) noticed that you're defaulting to 640x480 on RC1, which is a little much for RPIs to handle, but no matter, we can change our defaults to 320x240, but then you get the bad scaling for none-320x240 games (eg, banjo).

i tried your native_res branch, and it works great! i personally would suggest scrapping the various hard-coded resolution options, and just do 1x, 2x, etc native resolution, as i'm not sure how you would structure the options otherwise.

or you could have it something like:

        { CORE_NAME "-43screensize",
            "4:3 Resolution; native resolution|640x480|960x720|1280x960|1440x1080|1600x1200|1920x1440|2240x1680|2560x1920|2880x2160|3200x2400|3520x2640|3840x2880" },
        { CORE_NAME "-169screensize",
            "16:9 Resolution; native resolution|960x540|1280x720|1920x1080|2560x1440|3840x2160|4096x2160|7680x4320" },

(but then you don't get the benefit of consistent perfect scaling on higher resolution modes)

anyway, yeah, good option!

Papermanzero commented 4 years ago

Actually the output of the n64 is always 640x480. However the games can have different internal resolutions. I agree with the better overview of the scaling option with 1x, 2x, etc. However the question is from which starting point you scale. The internal resolution or the 640x480 native n64 output.

dankcushions commented 4 years ago

we should be following GLideN64 upstream IMO, which treats the internal resolution as 'native' (and has already implemented this, so we could hook in).

Papermanzero commented 4 years ago

Well, yes and no. Even gliden distinguish between internal and output resolution. https://github.com/gonetz/GLideN64/issues/2121 internal resolutions will always be scaled to 320x240 or 640x480.

From a user point of view it makes more sense to set the output resolution (240p or 480i) and scale from that up to 8k.

dankcushions commented 4 years ago

internal resolutions will always be scaled to 320x240 or 640x480.

@Papermanzero I don't think that's true. in current mupen64plus + gliden64, if I enable

# Show internal resolution.
ShowInternalResolution = True
# Show rendering resolution.
ShowRenderingResolution = True

and

# Frame buffer size is the factor of N64 native resolution.
UseNativeResolutionFactor = 1

and

[Video-General]

VerticalSync = True
Fullscreen = False
ScreenWidth = 1920
ScreenHeight = 1080

and play a game with a weird resolution, like banjo, i see

Internal Resolution 292x214
Rendering Resolution 292x214

and all the pixels are crisp.

Papermanzero commented 4 years ago

That‘s interesting because the VI code normally checks the resolution and scales it to either 240p or 480i.

https://github.com/gonetz/GLideN64/blob/29575624b94edf53bd6c72247d43eeaa1e03bf10/src/VI.cpp

To be honest, I did not look how mupen64plus behaves. Only into the libretro core.

dankcushions commented 4 years ago

the settings are GLideN64 settings, not mupen64plus. if you build this libretro core with the native_res fork it functions in the same way - the output is 292x214 (scaled to whatever your window/fullscreen resolution is set to). the native res functionality is not implemented in master.

however that code is interesting.. would have to track it through but the plugin seems to behave in the way i describe.