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:
bicarus
2026-08-02 03:35:07 -07:00
committed by GitHub
parent e7822aad8e
commit 1ec7528dac
5 changed files with 65 additions and 0 deletions
+47
View File
@@ -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(
+1
View File
@@ -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;
+3
View File
@@ -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();
}
+13
View File
@@ -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",
+1
View File
@@ -114,6 +114,7 @@ namespace launcher {
LoadHelloPopnMusicModule,
LoadGitaDoraModule,
GitaDoraTwoChannelAudio,
GitaDoraDisableFrameLimiter,
GitaDoraCabinetType,
GitaDoraLefty,
GitaDoraWailHold,