WIP: Support >60Hz (2nd try) - #585
Conversation
|
This time I was lazy and kept |
|
Ok, I think I have fixed the "Switching game modes can trigger a fake black screen" issue, by fixing how com_frameTime is calculated. At least on my (Linux) PC, the framerate is extremely stable now (with vsync disabled), but not at the rate configured with com_gameHz, but the next multiple of I guess I should try using floating point (double) times at least for the async tics, but probably I should also try how that all works on Windows and how it interacts with vsync. However, all this somehow feels wrong: I can't find it right now, but I think there are comments in the code stating that the tics are supposed to be incremented at 60Hz, and that this is supposed to be independent of the render framerate. On the other other hand, I don't see the point of that whole async thread for incrementing tics, no matter if the renderer is running in sync with the game or not. |
|
the console cursor also changes the flashing frequency with different values for com_gameHz |
74f40bd to
f8fa12f
Compare
true, I've also noticed this already, will add it to the list (I also know why it happens, just doing other changes first) |
f8fa12f to
c7e184e
Compare
|
I've pushed lots of changes in the last hours. Another is that the framerates should now be very close to what's configured with com_gameHz (unless VSync or a slow computer slow it down), because the timing of frame starts is now done with much more precision than full milliseconds. Most times in the game and engine still use full (integer) milliseconds, like before, so I wonder if this causes any issues or if starting the frames at the correct time is good enough for things to run smoothly. |
0916ab0 to
0bffae3
Compare
|
looks goot so far, played up to 1st airlock in mars city underground. There is an issue with the air supply though. It can be manipulated by changing com_gameHz while being outside com_gameHz 500 -> cycle airlock then set com_gameHz to a lower value changing com_gameHz to a higher value than configured has ofc the opposide effectl |
|
(rebased this branch again, to current master, so it includes the fix for #587) I'll look at the oxygen issue. |
|
Thanks for testing by the way, I appreciate that you're doing this, and how thorough you are! :) By the way, does dhewm3 at higher framerates feel smooth? |
|
It was a coincidence, I changed the setting while i was still in the airlock, but after I already initiated the airlock cycle. Desktop is set to 144Hz. I would not want to go back to 60Hz. |
I do, it's just that some code (incl. some scripts) uses the game tics that are incremented each frame, and at a higher framerate they increment faster.. But maybe I could change the logic to use a floating point tic number and then scale the added value each frame (at 120Hz add 0.5 instead of 1 tic), so the target tic would remain the same.. I just hope this isn't used by too much code besides the oxygen. Or I'd have to re-evaluate going back to 60Hz tics for the game code and only render at a higher framerate, but I'm not sure if this is feasible (and if there is even a point to that: what use are 120fps if nothing changes every second frame? but maybe something can be done without increasing the tic, I'll have to look at how the prediction code for multiplayer works, it might be related to this..)
why not? |
aaaaah. damn. No stutter, nothing. Feels very good so far. |
|
Here is a build for Windows: dhewm3-1.5.4pre-highfps_win32.zip This contains both the soft particles changes and this high FPS stuff. Other new features:
|
|
Based on the comment from @dezo2 at #250 (comment) I tested d3xp Erebus4 and yes, that new Imp near the start of the level definitely doesn't spawn (or drop?) like it should when running at 120 or 144 or 240 fps (it still seems to work fine at 60). It should come out of the black hole that arrow is pointing to: It eventually is there, at least if I stand directly below that hole, but at 60fps it drops down that hole pretty soon after that panel from the ceiling falls down after entering the room. Something else I noticed is that things completely fall apart when I change com_gameHz while the game is running (loading a savegame again fixes it). No idea what's going on there, or if the issue is in the scripts or C++ code or whatever. |
|
I got finally some time before going back to work so I just want to thank you Daniel for working on this. I tested the base game briefly and the game movement seems fine. What I found so far using com_gameHz 200 and 240 with VSync on a 240Hz VRR monitor: The crane at the start of map alphalabs3 doesn' t come up when I press the button and crashes the game (something about binding an object to itself). Which is strange because the chaingun firing rate is OK, so the scripts should be adjusted. There is a slight problem with 240Hz using VSync in cutscenes, where the audio sync (lipsync) drifts after a while even with default com_fixedTic 0. This is minor and can be fixed by running the engine at 200Hz (5ms int) - you can test it with map mars_city2 at the start, the survivor up the ladder there speaks relativelly long. I also noticed very brief frame skips when the Hz does not match the integer framerate like 240Hz and again they dissapear when using 200Hz or by setting com_fixedTic 1. The frequency of the skips seems to match the difference between int and float frametimes so at 240Hz 4.1666ms they are realtivelly far between. The imp in RoE should come down if you kick the panel under the hole - seems like the spawn is somehow tied to the panel position as it lands differently when it falls down before the imp at FPS >60. I will continue testing when I have some time. |
|
The crane crash is not caused by the scripts after all, I tried it with my old code and it needs the SetSteerSpeed adjustment in Physics_AF.h, it was this line in the code: But I thought you did something similar it in your new code, so not sure what's going on. |
|
Thanks for testing!
Hmm interesting theory - maybe the panel blocks the spawn position or something?
I just realized: I replaced that code with |
|
Just pushed a commit that fixes the crane (I tested the crane and didn't have crashes with 120, 240 or 60fps) |
|
Updated Windows build: dhewm3-1.5.4pre-highfps2_win32.zip By the way, some suggestions for testing:
|
|
Tested RoE yesterday with com_gameHz 200 and was able to run from start to finish without problems (apart from that one blocked imp in erebus4). No crashes or game breaking bugs, enemies went up/down the stairs to find me, grabber/slowmo/oxygen/enviro suit/machinery/elevators/bridges all worked as expected, so to me the code is already very usable. I will also try the base game but don't really expect any major problems there. BTW thanks for the F10 hidden menu tip, didn't even know about it. As for the second blocked imp, it's in the base game, map recycling2 (-494.73 1410.72 -11.75) 190.2, right after interaction with the left screen. Imp should jump out of his closet, but with FPS >= 85 (11ms) he will be blocked with a panel he tried to kick out. So similar situation to than one in RoE. Not sure if this can be fixed without breaking something else in the physics code. |
|
I just wanna point out that the original Doom 3 can now run at higher fps than BFG edition. What a time to be alive in. |
|
I may have found a fix for the blocked imps and potentially other enemies hidden behind wals and panels. This was caused by the STOP_SPEED in physics being too low for higher FPS, so by replacing a line in the source files Physics_RigidBody.cpp (base and d3xp): |
|
Crap, celebrated too soon. It works with 200 FPS but not with 144 or 120. The physics code is seriously weird. The STOP_SPEED has to be the culprit for these problems. |
also do that when loading a savegame, so those values are correct even if com_gameHz has a different value than it had when saving
it uses com_ticNumber to decide when to (not) draw - that must be scaled for shorter tics (at higher FPS)
turns out ResetSlowTimeVars() also does things one absolutely does *not* want at that point, like resetting frame counters and times that are *always* used, no matter if slowmo is enabled or not
in preparation of trying out TDM's fixes
they have *lots* of changes to physics code, partly to support mantling and movement in water, so it's not that easy to tell which are relevant for us. These are in things already identified as unstable here, so I'm hopeful that they help..
its steer speed must be adjusted for frame length
many thanks to dezo2 for suggesting these fixes! I think in the StepMove() case it's more of a hack than a fix - *maybe* the correct thing would be to accumulate the deltas over multiple frames when you got blocked, or something like this? - but as long as it doesn't break anything else I don't care..
at high framerates, grabbed stuff often fell down before being in front of the Grabber (where it could be thrown away again) Thanks to @dezo2 (again!) for pushing me in the right direction!
it's still possible, but a warning is shown and the setting in the menu only goes up to 250 now. Apart from physics getting wonkier the higher the framerate is, >250Hz breaks slow motion effects in RoE (d3xp), because it divides frametimes by four, and as the frametimes are integers, for >250Hz they're <= 3, so divided by four that's 0, which isn't good. Furthermore, I moved that setting to the Video settings, so it's closer to related settings like VSync and display refreshrate. While at it, I made sure that `com_showFPS 2` can be configured in the menu as well (it still assumed it's a bool). Last but not least I fixed a misleading variable name in Win_InitTime()
to prevent them from jumping so much at high framerates
So far dhewm3 ignored that CVar, now it tries to set that refreshrate Also display the current refreshrate in the Dhewm3SettingsMenu, but no way to configure it there yet.
9bbd638 to
41a3741
Compare
|
I rebased this branch to current master. Doing this wasn't trivial, because I merged and then changed some parts of this branch to master for the "smoother timing at 60Hz" feature, so it's possible that I broke something - testing is welcome! :)
I don't know. |
|
Not sure why but this branch doesn't work with Sikkmod, game crashes after trying to load the opening FMV. 1.5.5 RC2 works okay. |
|
suggested patch by Klaus: diff --git a/neo/d3xp/Player.cpp b/neo/d3xp/Player.cpp
index cded54d5..158657d7 100644
--- a/neo/d3xp/Player.cpp
+++ b/neo/d3xp/Player.cpp
@@ -6931,7 +6931,9 @@ void idPlayer::AdjustBodyAngles( void ) {
}
if ( blend ) {
- legsYaw = legsYaw * 0.9f + idealLegsYaw * 0.1f;
+ static const float tau = -16.0f / idMath::Log( 0.9f );
+ const float a = 1.0f - idMath::Exp( -gameLocal.gameMsec / tau );
+ legsYaw = legsYaw * (1.0f - a) + idealLegsYaw * a;
}
legsAxis = idAngles( 0.0f, legsYaw, 0.0f ).ToMat3();
animator.SetJointAxis( hipJoint, JOINTMOD_WORLD, legsAxis );
diff --git a/neo/d3xp/physics/Force_Drag.cpp b/neo/d3xp/physics/Force_Drag.cpp
index 581a039a..0df2bcaa 100644
--- a/neo/d3xp/physics/Force_Drag.cpp
+++ b/neo/d3xp/physics/Force_Drag.cpp
@@ -67,7 +67,7 @@ idForce_Drag::Init
*/
void idForce_Drag::Init( float damping ) {
if ( damping >= 0.0f && damping < 1.0f ) {
- this->damping = damping;
+ this->damping = idMath::Pow( damping, 60.0f / gameLocal.gameHz );
}
}
diff --git a/neo/d3xp/physics/Force_Grab.cpp b/neo/d3xp/physics/Force_Grab.cpp
index 169e01bd..52557169 100644
--- a/neo/d3xp/physics/Force_Grab.cpp
+++ b/neo/d3xp/physics/Force_Grab.cpp
@@ -187,7 +187,8 @@ void idForce_Grab::Evaluate( int time ) {
if ( distanceToGoal < 16.f ) {
v = physics->GetAngularVelocity(id);
if ( v.LengthSqr() > Square(8) ) {
- physics->SetAngularVelocity( v * 0.99999f, id );
+ float angDamping = idMath::Pow( 0.99999f, 60.0f / gameLocal.gameHz );
+ physics->SetAngularVelocity( v * angDamping, id );
}
}
}
diff --git a/neo/game/Player.cpp b/neo/game/Player.cpp
index 63ddce16..380a16eb 100644
--- a/neo/game/Player.cpp
+++ b/neo/game/Player.cpp
@@ -5827,7 +5827,9 @@ void idPlayer::AdjustBodyAngles( void ) {
}
if ( blend ) {
- legsYaw = legsYaw * 0.9f + idealLegsYaw * 0.1f;
+ static const float tau = -16.0f / idMath::Log( 0.9f );
+ const float a = 1.0f - idMath::Exp( -gameLocal.gameMsec / tau );
+ legsYaw = legsYaw * (1.0f - a) + idealLegsYaw * a;
}
legsAxis = idAngles( 0.0f, legsYaw, 0.0f ).ToMat3();
animator.SetJointAxis( hipJoint, JOINTMOD_WORLD, legsAxis );
diff --git a/neo/game/physics/Force_Drag.cpp b/neo/game/physics/Force_Drag.cpp
index 581a039a..0df2bcaa 100644
--- a/neo/game/physics/Force_Drag.cpp
+++ b/neo/game/physics/Force_Drag.cpp
@@ -67,7 +67,7 @@ idForce_Drag::Init
*/
void idForce_Drag::Init( float damping ) {
if ( damping >= 0.0f && damping < 1.0f ) {
- this->damping = damping;
+ this->damping = idMath::Pow( damping, 60.0f / gameLocal.gameHz );
}
}
they're similar to changes I already did in other similar places places
|
|
I assume this is behind 1.5.5 RC3? |
|
It feels like progress on this has stalled. Thing is, it works very well at least for me, and if there are any game-breaking bugs they're either very minor or I have been lucky enough to not encounter them yet. But I'm stuck on an old dev build and 1.5.5 was released recently, so I'm basically torn between the newer general improvements and actually getting use out of a high refresh-rate monitor. Maybe there's value in incorporating the >60Hz changes already present and locking the modification of the com_gameHz variable behind a checkbox in the GUI or something. Basically identify it as EXPERIMENTAL or something, user beware. Or not have it visible in the GUI for now, just leave it as a variable you'd have to know exists already in order to modify. |
|
Hi, first of all thank you for this build, it works great! Would it be possible to also provide the d3le.dll for the Lost Mission episode, compiled against this HFR build? The official one from the release page is unfortunately not compatible. That would be amazing, thanks! |
I don't think enough of the game has been tested on multiple different framerates. I was planning to do another full playthrough, but unfortunately never found the time to do so. If we get more people to test, and provide debug videos and logs, it would help immensely. The biggest challenge I see here is multiplayer. It is still completely broken, mostly because the Doom 3 MP is, by design, dependent on a fixed framerate. |
|
Never played Doom3, but once I saw this mod year ago wanted to give it a try. |
|
please release builds of this pr at least in your fork, so I don't have to search for an outdated .zip on this page or compile it |
|
What's the state of this? Artifacts are expired again :) |
|
Are you guys aware of DUDE? https://github.com/Inkub0/dude Apparently it can render beyond 60 FPS while rendering physics at 60 Hz? If I understand correctly |
|
Yes, I'm aware. It seems to be inspired by the approach suggested by Yamagi here: http://github.com/dhewm/dhewm3/pull/310 I've sent a dhewm3 implementation of Yamagi's approach in this PR a few weeks ago: #771 But it needs testing. So if you can build that branch and run it across a few maps, that would be very appreciated. |
|
Interpolation is particularly interesting because it should get around any multiplayer limitations, besides guaranteeing game logic is functional. |
|
Just to add fuel to the fire, this individual has an open source Quake 4 port with high FPS support: https://github.com/themuffinator/openQ4 That said if you don't like the claude commits in DUDE, you ain't gonna like openQ4. The creator isn't exactly shy about their love of AI: https://github.com/themuffinator |





Based on @dezo2's patch (see also), but adjusted to make the framerate configurable with the
com_gameHzCVar + my own fixes, also some ideas from Stradex' branch.Very much WIP, and no guarantees this will work out
TODO
Potential bugs that have been observed with various attempts of running dhewm3 with >60Hz and that are worth testing:
com_fixedTic -1, might not be relevant here?)I can still reproduce this bug. I think it's related to counting tics (com_ticNumber?) and then multiplying it with USERCMD_MSEC and comparing the result to Sys_Milliseconds() or something, combined with one mod having a differentcom_gameHzvalue than the other, so tics are longer/shorter. Needs more investigation..Should be fixed
But at least (unlike in Stradex/simonedibilio's branch) they don't break every time you change
com_gameHz, so from now on they should be stable again.idGame::RunFrame()multiple times if com_gameHz is too low