mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
gitadora: option to disable frame limiter (#848)
## Link to GitHub Issue or related Pull Request, if one exists n/a ## Description of change There is a patch for GITADORA series that fixes frame pacing on modern Windows. Turn it into a signature patch and embed it into the game. ## Testing should work for all 64-bit gitadora versions, pre-GWD
This commit is contained in:
@@ -31,6 +31,7 @@ namespace games::gitadora {
|
||||
|
||||
// settings
|
||||
bool TWOCHANNEL = false;
|
||||
bool DISABLE_FRAME_LIMITER = false;
|
||||
std::optional<unsigned int> CAB_TYPE = std::nullopt;
|
||||
bool P1_LEFTY = false;
|
||||
bool P2_LEFTY = false;
|
||||
@@ -65,6 +66,46 @@ namespace games::gitadora {
|
||||
|
||||
return CreateDirectoryA(lpPathName, lpSecurityAttributes);
|
||||
}
|
||||
|
||||
// libshare-pj paces mainloop with separate 12 ms and 16 ms waits. these waits
|
||||
// interfere with the game's normal display synchronization on modern Windows
|
||||
// and can hold a nominal 60 FPS game near 58 FPS. locate the instruction
|
||||
// sequences at runtime so the fix does not depend on per-version file offsets.
|
||||
static void disable_mainloop_frame_limiter(HMODULE sharepj_module) {
|
||||
if (!sharepj_module) {
|
||||
return;
|
||||
}
|
||||
|
||||
// both limiters have the same shape, only the millisecond target xx differs
|
||||
// (0Ch for the 12 ms limiter, 10h for the 16 ms one):
|
||||
//
|
||||
// 48 83 F8 xx: cmp rax, xx; compare elapsed frame time with the target
|
||||
// 73 10: jae +10h; skip the wait once the target has elapsed
|
||||
// B9 xx 00 00 00: mov ecx, xx; load the target
|
||||
// 48 2B C8: sub rcx, rax; calculate the remaining wait time
|
||||
// 74 06: je +6h; skip the following six-byte Sleep call if no wait remains
|
||||
//
|
||||
// changing jae (73h) to jmp (EBh) makes each block always take its existing
|
||||
// skip path, which bypasses only the associated Sleep call and leaves the 10h
|
||||
// branch displacement and every other wait untouched.
|
||||
const auto limiter_12ms_disabled = replace_pattern(
|
||||
sharepj_module,
|
||||
"4883F80C7310B90C000000482BC87406",
|
||||
"????????EB??????????????????????", 0, 0);
|
||||
const auto limiter_16ms_disabled = replace_pattern(
|
||||
sharepj_module,
|
||||
"4883F8107310B910000000482BC87406",
|
||||
"????????EB??????????????????????", 0, 0);
|
||||
|
||||
if (!limiter_12ms_disabled || !limiter_16ms_disabled) {
|
||||
log_fatal(
|
||||
"gitadora",
|
||||
"failed to disable libshare-pj mainloop frame limiter (-gdnoframelimiter), ensure patch is not already applied");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("gitadora", "successfully disabled libshare-pj mainloop frame limiter (-gdnoframelimiter)");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -687,6 +728,12 @@ namespace games::gitadora {
|
||||
HMODULE system_module = libutils::try_module("libsystem.dll");
|
||||
|
||||
// patches
|
||||
#ifdef SPICE64
|
||||
if (DISABLE_FRAME_LIMITER && !is_arena_model()) {
|
||||
disable_mainloop_frame_limiter(sharepj_module);
|
||||
}
|
||||
#endif
|
||||
|
||||
detour::inline_hook((void *) eam_network_detected_ip_change, libutils::try_proc(
|
||||
sharepj_module, "eam_network_detected_ip_change"));
|
||||
detour::inline_hook((void *) eam_network_settings_conflict, libutils::try_proc(
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace games::gitadora {
|
||||
|
||||
// settings
|
||||
extern bool TWOCHANNEL;
|
||||
extern bool DISABLE_FRAME_LIMITER;
|
||||
extern std::optional<unsigned int> CAB_TYPE;
|
||||
extern bool P1_LEFTY;
|
||||
extern bool P2_LEFTY;
|
||||
|
||||
@@ -644,6 +644,9 @@ int main_implementation(int argc, char *argv[]) {
|
||||
if (options[launcher::Options::LoadGitaDoraModule].value_bool()) {
|
||||
attach_gitadora = true;
|
||||
}
|
||||
if (options[launcher::Options::GitaDoraDisableFrameLimiter].value_bool()) {
|
||||
games::gitadora::DISABLE_FRAME_LIMITER = true;
|
||||
}
|
||||
if (options[launcher::Options::GitaDoraCabinetType].is_active()) {
|
||||
games::gitadora::CAB_TYPE = options[launcher::Options::GitaDoraCabinetType].value_uint32();
|
||||
}
|
||||
|
||||
@@ -1202,6 +1202,19 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.category = "Game Options",
|
||||
.quick_setting_category = "Game",
|
||||
},
|
||||
{
|
||||
.title = "GitaDora Disable Frame Limiter (EXPERIMENTAL)",
|
||||
.name = "gdnoframelimiter",
|
||||
.desc = "Only for GITADORA to GALAXY WAVE; not for XG series or Arena Model.\n\n"
|
||||
"Game engine's built-in frame limiter can result in unstable frame pacing "
|
||||
"(around 56-58 FPS) on modern Windows. Turning this on disables that and "
|
||||
"forces the game to rely on V-Sync instead, resulting in a stable FPS.\n\n"
|
||||
"Ensure your monitors are set to 60Hz.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "GitaDora",
|
||||
.category = "Game Options",
|
||||
.quick_setting_category = "Game",
|
||||
},
|
||||
{
|
||||
.title = "GitaDora Cabinet Type",
|
||||
.name = "gdcabtype",
|
||||
|
||||
@@ -114,6 +114,7 @@ namespace launcher {
|
||||
LoadHelloPopnMusicModule,
|
||||
LoadGitaDoraModule,
|
||||
GitaDoraTwoChannelAudio,
|
||||
GitaDoraDisableFrameLimiter,
|
||||
GitaDoraCabinetType,
|
||||
GitaDoraLefty,
|
||||
GitaDoraWailHold,
|
||||
|
||||
Reference in New Issue
Block a user