Lyall / MGSHDFix

A fix that adds custom resolutions, ultrawide support and much more to the Metal Gear Solid Master Collection.
MIT License
376 stars 8 forks source link

MGS2/MGS3: add hook/setting for anisotropic filtering #31

Closed emoose closed 8 months ago

emoose commented 8 months ago

Game currently doesn't apply any kind of anisotropic filtering, leaving textures get very muddy in the distance, there's some ways to force this in driver settings but not sure how perfect driver forcing is (and a lot of people probably don't know they can force it via drivers)

In D3D11 it seems for anisotropy to be used a D3D11_SAMPLER_DESC has to be setup with both .Filter = D3D11_FILTER_ANISOTROPIC and also .MaxAnisotropy = anisoAmount

Fortunately for us it looks like game already creates D3D11_SAMPLER_DESC instances already, and uses them with CreateSamplerState etc, but it's only applying worse filters like D3D11_FILTER_MIN_MAG_MIP_POINT / D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT, etc...

(in MGS3 0x14004D310 / CRenderBackend::SetTextureFilter chooses one of those filters above, and 0x140055DE0 / CD3DCachedDevice::SetSamplerState then sets it in the D3D11_SAMPLER_DESC struct)

Sadly we can't just patch the ID of those filters being used over to D3D11_FILTER_ANISOTROPIC since we also have to setup the .MaxAnisotropy field of it too, best way I could find for that was a hook inside SetSamplerState when it's setting up the .Filter field, there wasn't really much room there to hook but was able to find a way to get it working, and also keep the small optimization they use in that func so it only applies the filter when it's being changed from previous one.

Anisotropy makes a pretty big difference in MGS3, before:

23-10-30_00-06-41-097_METAL_GEAR_SOLID3

after:

23-10-30_00-08-02-535_METAL_GEAR_SOLID3

The hook seems to apply fine in MGS2 too but I couldn't really notice much difference there, guess the camera maybe makes it harder to see...

This might need more testing before being merged, haven't really got that far in the games yet so only tried it around starting areas, maybe something later on could break with it.

If anyone wants to help test it here's a build with it included, install on top of 0.7 & edit the INI to enable it: MGSHDFix-aniso-fixed.zip

(E: build should have fixed pattern scan now)

emoose commented 8 months ago

Also wasn't too sure where to put it in INI file, didn't really seem like it needed a section to enable & then set value since we can just treat setting it to non-zero as enabling it, putting it under custom resolution seemed the closest fit but idk really, feel free to move if you like.

KoKlusz commented 8 months ago

Off topic (?) but can MSAA also be enabled? HD Collection used it 2x MSAA on PS3 and X360 but apparently MSAA is disabled in Master Collection.

emoose commented 8 months ago

Looks like they added some MSAA support in the CBaseTexture functions, but the main d3d swapchain init just sets it as default (samples = 1, quality = 0), so seems like it does get left disabled.

Not sure how much work it'd be to get it working, maybe better off using something like DSR instead.

E: hm, apparently setting MSAA on the swapchain isn't really recommended, should be set on the render target instead.. looks like the CBaseTexture MSAA stuff I mentioned above could maybe be used for it, render target creation does go through it at least, but seems they use kAA_None for all of them, need to play with it more some time.

Lyall commented 8 months ago

Looks great. Should the anisotropic value maybe be clamped? If a user sets it to a value higher than 16 would it cause any issues?

ShizCalev commented 8 months ago

The hook seems to apply fine in MGS2 too but I couldn't really notice much difference there, guess the camera maybe makes it harder to see...

image

Peeking around corners appears to be the largest problem area with MGS2.

ShizCalev commented 8 months ago

Looks great. Should the anisotropic value maybe be clamped? If a user sets it to a value higher than 16 would it cause any issues?

diminishing returns to the point where (to my knowledge) most hardware doesn't bother supporting anything higher than 16 anyway. might as well just clamp.

emoose commented 8 months ago

Ah yeah probably should add a clamp to it, will check if it has to be power-of-2 as well, and write something in log if user put in something invalid.

E: hm, added clamp to 0-16 below, didn't add non-power-of-2 check since what I read sounded like it'd be fine, but looks like that might be breaking AF actually.. will check it in a sec

E2: oh actually I'm getting pattern scan fail on it for some reason now, hm..

emoose commented 8 months ago

Added clamp & log message, seems non-power-of-2 values should work fine, 15x looked pretty similar to 16x at least.

(thought 15x might not be working but seems I'd just broke pattern scan in the log output commit, should be fine now 😅)

KoKlusz commented 8 months ago

Not sure how much work it'd be to get it working, maybe better off using something like DSR instead.

Yeah, but the problem with DSR is post process scaling, or rather lack of it (I'm not holding my breath that it will be easy to fix, if it was Konami would probably do it). Plus, enabling MSAA could open the door to forcing SGSSAA via Nvidia drivers.

MarioTainaka commented 8 months ago

Amazing work so far! I can't keep up with all these updates. Wouldn't Forcing AF via the driver be less work compared to implementing it an ini tho?

Lyall commented 8 months ago

Amazing work so far! I can't keep up with all these updates. Wouldn't Forcing AF via the driver be less work compared to implementing it an ini tho?

It has a few benefits doing it this way. It's vendor-agnostic so you can get 16x AF on a Steam Deck, an AMD GPU, an Nvidia GPU or even an Intel one. Also forcing 16x AF through the NVCP on Nvidia cards can cause issues (very rarely to be fair, Starfield is a recent one that I can recall). Also with it defaulting to 16x in the configuration file, it's one less thing for people to think about.

MarioTainaka commented 8 months ago

Amazing work so far! I can't keep up with all these updates. Wouldn't Forcing AF via the driver be less work compared to implementing it an ini tho?

It has a few benefits doing it this way. It's vendor-agnostic so you can get 16x AF on a Steam Deck, an AMD GPU, an Nvidia GPU or even an Intel one. Also forcing 16x AF through the NVCP on Nvidia cards can cause issues (very rarely to be fair, Starfield is a recent one that I can recall). Also with it defaulting to 16x in the configuration file, it's one less thing for people to think about.

Ah thank you for clarifying. I always assumed AF just worked properly regardless of vendors their drivers