Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Builtin frame limiter #35

Open
bangstk opened this issue Jul 3, 2019 · 21 comments
Open

Request: Builtin frame limiter #35

bangstk opened this issue Jul 3, 2019 · 21 comments
Labels
enhancement New feature or request

Comments

@bangstk
Copy link

bangstk commented Jul 3, 2019

An option to set an arbitrary Vsync or maximum FPS would be nice, because Jedi Knight has strange behavior. At 48fps and above, weapons start playing animations too fast and frames start becoming duplicated, resulting in cases such as the game looking like 30fps at 60fps with weapons animating twice as fast as they should.

A way to set the maximum framerate to 47 (or any user selectable number) would be optimum for Jedi Knight.

Other alternatives such as RivaTuner and Aqrit's ddraw wrapper allow this functionality for the base game but they don't work well with jkgfxmod as it is a wrapper of its own.

@jdmclark
Copy link
Owner

jdmclark commented Jul 8, 2019

Hi @bangstk

Thanks for the suggestion. This seems reasonable. I'm also inclined to make 48 FPS the default cap, since as you noted there is no real advantage to exceeding that rate.

@jdmclark jdmclark added the enhancement New feature or request label Jul 8, 2019
@SirYodaJedi
Copy link
Contributor

SirYodaJedi commented Jul 8, 2019

I'm also inclined to make 48 FPS the default cap.

Please don't. It'll actually make it worse for those of us without variable refresh rate monitors.

@bangstk
Copy link
Author

bangstk commented Jul 9, 2019

You should try it with one of the utilities I mentioned (and without JkGfxMod). It's astronomically and objectively smoother than the game running at 60FPS. Also make sure it's 47FPS, I think 48FPS is noticeably much more stuttery because that is when in-game frame duplication starts happening, but it does not at 47.

If your monitor only displays at 60Hz, your OS is still going to duplicate frames to make it output at 60Hz anyways. But the number of duplicated frames will be much less than what the game itself does at 60FPS.

I know on paper forcing 47FPS into a 60FPS monitor seems like it would be wrong and inconsistent, but once you try it with Jedi Knight it's like being able to see again after having eye surgery.

I think Aqrit's wrapper was very inconsistent with frame timing until I modified the code myself to use a higher resolution timer, but maybe RivaTuner does better out of the box.

@SirYodaJedi
Copy link
Contributor

SirYodaJedi commented Jul 9, 2019

I have tried those methods. I find the default method (frame duplication) to much less visually irritating than when it is running at a capped 47 FPS (which causes something similar to 3:2 pulldown). The camera updates every other refresh, rather than every 2-3 refreshes, resulting in hard pans (such as rotating your head, you do that a lot in this genre) not being juddery the way they are on NTSC DVDs.

If you are playing on a higher refresh rate, such as 120 or 144 (without VRR), the judder is much less noticeable, and therefore more bearable. So no, it isn't objectively better, but rather a tradeoff between judder and stutter.

@KainXVIII
Copy link

And how to make game run in 60 fps? Mine only works with 30 fps cap (and awful stuttering)

@bangstk
Copy link
Author

bangstk commented Nov 29, 2019

I don't think it's possible, I've seen some tests elsewhere with COG scripting that definitively shows that 47FPS is the highest sim rate the game can achieve unless someone can figure out how to modify the .exe to remove the cap/up the sim rate. Once FPS gets higher than 47 it seems physics stop updating as often as FPS other than some camera movement in certain situations.

http:https://www.jkhub.net/forums/viewtopic.php?p=18681#18681

@KainXVIII
Copy link

KainXVIII commented Nov 29, 2019

I don't think it's possible, I've seen some tests elsewhere with COG scripting that definitively shows that 47FPS is the highest sim rate the game can achieve unless someone can figure out how to modify the .exe to remove the cap/up the sim rate. Once FPS gets higher than 47 it seems physics stop updating as often as FPS other than some camera movement in certain situations.

http:https://www.jkhub.net/forums/viewtopic.php?p=18681#18681

Well, i'm ok even with 30 fps cap, but smooth 30 fps, stuttering is terrible for me.
UPD - capping 30 fps with RTSS helps a lot! Maybe capping fps through jkgm.json will be useful feature?

@jdmclark jdmclark mentioned this issue Jan 13, 2020
@TP555
Copy link

TP555 commented Apr 21, 2020

@KainXVIII

Yes , but the Mod , and low Res , you can get about 100FPS , the main problem is the Physics are running too fast.

With 30FPS , it runs smooth

im for a Option 30 or 60FPS , but 60 with Adjust the Physics when possible , like the Weapons Move on fast Running , runs too fast in compare with 30FPS

Vsync is ok , but can Cause lags , when the Target FPS isn't stable , that is why it gives alternative Vsync Options like Adaptive , Fast , and even Freesync (AMD) , Gsync (Nvidia)

@jdmclark
Copy link
Owner

As an interim measure, I'm getting ready to push a change that will add a simple vsync option. Vsync will now be disabled by default. This means JkGfxMod will depart from the current default behavior, which enables vsync unless it has been explicitly disabled in the driver control panel.

Rationale is per the above discussion, but to elaborate:

JK's internal update rate is 48 Hz, without state interpolation. If you play JK on a 60 Hz monitor with vsync enabled, the game will look like this:

Frame 0
Frame 0
Frame 1 (12.5 ms late)
Frame 2 (8.3 ms late)
Frame 4

Put simply, this looks disgusting: the game looks like it is constantly stuttering and dropping frames when vsync is enabled. It is almost certainly not what people want, but it's also not obvious to most people that it could be a source of this kind of problem.

Unfortunately, there is a trade-off. Besides tearing, JK also doesn't scale the first person weapon animation speed against frame time. This makes the first person weapon model waggle rapidly when the game is running at high framerates. On balance though, I think the stuttering/dropped frames issue is much worse than the tearing and animation problem.

jdmclark added a commit that referenced this issue Nov 17, 2020
As noted. Vsync is disabled by default. See #35 for discussion.
@bangstk
Copy link
Author

bangstk commented Nov 17, 2020 via email

@jdmclark
Copy link
Owner

That sounds good. Any to plans to allow specifying arbitrary framerate cap? 48Hz folds neatly into today's 144Hz monitors, and being able to cap the game would at least allow for correct weapon animations

I think it's a good idea, but I don't have a good variable refresh rate display to properly test the change. I'll review the PR if someone submits one, but otherwise it will probably have to wait until the next time I replace a monitor.

Aside: I might be misunderstanding, but I think variable refresh rate is the principal use case for framerate capping. If you already have a 144 Hz monitor and can run the game at that rate, you should be good to go with just vsync already. It seems like this would mostly be useful for when you want to run the game at a non-native refresh rate, like 48 or 96 Hz.

@bangstk
Copy link
Author

bangstk commented Dec 26, 2020

It seems like this would mostly be useful for when you want to run the game at a non-native refresh rate, like 48 or 96 Hz.

I think that is a very good reason; since 48fps is the highest possible fps the game can achieve without any bugs. I believe an effort should be made to support it since not many players of the game know about it at all, because currently the only way to get it is to use external tools like RivaTuner. Stacking on a bunch of patches and wrappers is not ideal. It should be an option in JkGfxMod.

@shinyquagsire23
Copy link

shinyquagsire23 commented Jan 4, 2021

I actually just figured out how to unlimit the framerate when testing some OpenJKDF2 function rewrites with my 120FPS monitor, so I can actually explain a bit of the weird jitter:

The first issue is the game has its own framerate limiting where it will not update the game unless it reaches 20ms from the last update, seen here: https://github.com/shinyquagsire23/OpenJKDF2/blob/d7e836b6860c4d460829bb034f9eddf0d7a6ed1f/df2_reimpl/src/Main/jkMain.c#L136

The second issue is that player physics in particular are coded to run at 50FPS, presumably for multiplayer? seen here: https://github.com/shinyquagsire23/OpenJKDF2/blob/5793172c38d564f2e65280c9ad6d104f7c79bb3d/df2_reimpl/src/World/sithSector.c#L169

You can patch out the former by opening JK.EXE in a hex editor and searching for 83 C0 14 3B F0 and changing the 14 to 01 for all three occurrences (marked in my reversing at jkMain_gui_loop, jkMain_GameplayTick, and jkMain_EscapeMenuTick). The latter I patched by searching 83 78 0C 0A 75 0F 8B 54 24 08 52 50 E8 C8 0E 00 00 83 C4 08 c3 and replacing it with 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 (nopped out). It's roughly equivalent to commenting out these lines, but I think a better solution @jdmclark might be to hook and make the sithSector_ThingPhysPlayer call dependent on net_isMulti

Most of the game's logic already uses millisecond deltas so I haven't actually noticed any bugs in singleplayer, but the animations don't seem to interpolate that well in some places.

@jdmclark
Copy link
Owner

jdmclark commented Jan 4, 2021

@shinyquagsire23

Interesting discovery! That isn't what I expected. I can't say for sure, but that code smells like a late bug fix to me (probably to hack around the kinds of simulation instability problems that we know a variable timestep causes). If that's the case, disabling it would cause problems, but I wouldn't expect them to be immediately obvious.

I think the best solution of all would be to use OpenJKDF2 to implement a correct fixed timestep and a renderer that can do state interpolation, when such an effort becomes feasible.

@bangstk
Copy link
Author

bangstk commented Jan 10, 2021

I actually just figured out how to unlimit the framerate when testing some OpenJKDF2 function rewrites with my 120FPS monitor, so I can actually explain a bit of the weird jitter:

The first issue is the game has its own framerate limiting where it will not update the game unless it reaches 20ms from the last update, seen here: https://github.com/shinyquagsire23/OpenJKDF2/blob/d7e836b6860c4d460829bb034f9eddf0d7a6ed1f/df2_reimpl/src/Main/jkMain.c#L136

The second issue is that player physics in particular are coded to run at 50FPS, presumably for multiplayer? seen here: https://github.com/shinyquagsire23/OpenJKDF2/blob/5793172c38d564f2e65280c9ad6d104f7c79bb3d/df2_reimpl/src/World/sithSector.c#L169

You can patch out the former by opening JK.EXE in a hex editor and searching for 83 C0 14 3B F0 and changing the 14 to 01 for all three occurrences (marked in my reversing at jkMain_gui_loop, jkMain_GameplayTick, and jkMain_EscapeMenuTick). The latter I patched by searching 83 78 0C 0A 75 0F 8B 54 24 08 52 50 E8 C8 0E 00 00 83 C4 08 c3 and replacing it with 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 (nopped out). It's roughly equivalent to commenting out these lines, but I think a better solution @jdmclark might be to hook and make the sithSector_ThingPhysPlayer call dependent on net_isMulti

Most of the game's logic already uses millisecond deltas so I haven't actually noticed any bugs in singleplayer, but the animations don't seem to interpolate that well in some places.

Awesome work! Just one question though, what happens to first person weapon animations above 47fps? With the old logic they start playing faster but only above 47fps.

I think the best solution of all would be to use OpenJKDF2 to implement a correct fixed timestep and a renderer that can do state interpolation, when such an effort becomes feasible.

Probably the best study example for this would be the Chimera mod for Halo, which is another dll injection, but fully interpolates model animations and positions between 30fps up to whatever fps you want.

@shinyquagsire23
Copy link

Awesome work! Just one question though, what happens to first person weapon animations above 47fps? With the old logic they start playing faster but only above 47fps.

I had someone else test the patch and on their end it did have issues, but apparently framelimiting it externally w/ dgvoodoo to 48FPS felt smoother to them? Which makes sense to me at least, I feel like the physics stepping probably is the worst offender since player input applies acceleration to the player object -> head rot + movement might skip frames. I haven't actually noticed weapon animations being too fast on my end though, might be a WINE vs Windows thing somehow? Or I misremember how fast it should be.

Probably the best study example for this would be the Chimera mod for Halo, which is another dll injection, but fully interpolates model animations and positions between 30fps up to whatever fps you want.

Yeah I got OpenJKDF2 to work with WINE at least so I might just maintain something similar, ended up fixing aspect ratios too w/ some ifdefs and I feel like weapon/other interpolation wouldn't be too difficult to fix. My vague model though is something between the N64 decomps and OpenRCT, eventually replacing the client entirely if I can.

@bangstk
Copy link
Author

bangstk commented Jan 10, 2021

Just applied the hex changes myself and can confirm this also fixes the weapon animations speed. They play at the correct speed even at 60fps.

I used the saber altfire as a test, with the correct speed you can see that the second slash matches up with the third person animation.

Awesome news and thanks again! The game feels so much fresher.

@bangstk
Copy link
Author

bangstk commented Jan 10, 2021

Last thing I noticed then, these hex strings don't seem to exist in the Steam/GoG versions of the JK.EXE executables. Do they include addresses that might be different in them? Any other instructions/hex strings nearby that are likely to be the same?

EDIT: Nevermind, it's there in the GoG version, the Steam EXE seems to have its code section compressed or encrypted in some way. Strange

@bangstk
Copy link
Author

bangstk commented Jan 10, 2021

And lastly: to bring the discussion back to JkGfxMod, I would still advocate for allowing user to set an arbitrary framerate limit. Reason being that now with the fixed FPS patching code found by @shinyquagsire23 the game does appear to speed up at extreme framerates (my computer can run it at about 800 FPS without vsync and at that speed the game physics are certainly about 4-5x faster than they should be) so vsync is required for JkGfxMod to work with it.

@DaerosTrollkiller
Copy link

Throwing my hat into the ring for allowing the user to set a frame rate limit.

@KainXVIII
Copy link

Throwing my hat into the ring for allowing the user to set a frame rate limit.

You should move to this project https://github.com/shinyquagsire23/OpenJKDF2 (which includes jkgfxmod)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants