Add more rexcrt entries, add guest framerate counter

This commit is contained in:
Your Name
2026-03-09 09:57:33 -05:00
parent 16c99ffcf3
commit f87cc7dde7
5 changed files with 136 additions and 1 deletions
+1
View File
@@ -14,6 +14,7 @@ include(generated/rexglue.cmake)
# Sources
set(AC6RECOMP_SOURCES
src/main.cpp
src/render_hooks.cpp
)
if(WIN32)
+31
View File
@@ -21,6 +21,14 @@ memcpy = 0x82382F18
memmove = 0x82383870
memset = 0x823830F0
XMemCpy = 0x82382A90
strncmp = 0x82383930
strncpy = 0x82382370
strchr = 0x82382190
strstr = 0x82382520
strrchr = 0x8238E810
strcpy_s = 0x823821D0
memcpy_s = 0x82381DE0
memmove_s = 0x823809F0
[functions]
0x82090000 = { name = "rex_sub_82090000" }
@@ -10544,3 +10552,26 @@ XMemCpy = 0x82382A90
0x823E1250 = { name = "rex_sub_823E1250" }
0x823E1320 = { name = "rex_sub_823E1320" }
0x823E13F0 = { name = "rex_sub_823E13F0" }
# ---------------------------------------------------------------------------
# Midasm hooks — 60fps unlock (Phase 1)
# ---------------------------------------------------------------------------
# Skip `ori r3,r3,2` that sets vsync swap interval to 2 (30fps lock).
# When hook returns true, jumps past the ori to 0x821F075C.
[[midasm_hook]]
address = 0x821F0758
name = "ac6VsyncIntervalHook"
jump_address_on_true = 0x821F075C
# Override the FPS divisor in the delta time formula.
# r29 holds the divisor (default 60); hook sets it to 30 when unlocked.
[[midasm_hook]]
address = 0x821EFD38
name = "ac6DeltaDivisorHook"
registers = ["r29"]
# Record frame timestamps before VdSwap for timing overlay.
[[midasm_hook]]
address = 0x821F0664
name = "ac6PresentTimingHook"
+10 -1
View File
@@ -7,6 +7,9 @@
#include <rex/cvar.h>
#include <rex/rex_app.h>
#include <rex/ui/overlay/debug_overlay.h>
#include "render_hooks.h"
REXCVAR_DECLARE(bool, vfetch_index_rounding_bias);
@@ -26,8 +29,14 @@ class Ac6recompApp : public rex::ReXApp {
REXCVAR_SET(vfetch_index_rounding_bias, true);
}
void OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) override {
debug_overlay()->SetStatsProvider([] {
auto gs = ac6::GetFrameStats();
return rex::ui::FrameStats{gs.frame_time_ms, gs.fps, gs.frame_count};
});
}
// void OnPostSetup() override {}
// void OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) override {}
// void OnShutdown() override {}
// void OnConfigurePaths(rex::PathConfig& paths) override {}
};
+71
View File
@@ -0,0 +1,71 @@
/**
* @file render_hooks.cpp
* @brief Mid-asm hooks for vsync interval, frame timing, and 60fps unlock.
*/
#include "render_hooks.h"
#include <atomic>
#include <chrono>
#include <rex/cvar.h>
#include <rex/ppc/types.h>
REXCVAR_DEFINE_BOOL(ac6_unlock_fps, false, "AC6", "Unlock frame rate to 60fps");
using Clock = std::chrono::steady_clock;
namespace {
// Frame timing state (written on render thread, read from UI thread).
std::atomic<double> g_frame_time_ms{0.0};
std::atomic<double> g_fps{0.0};
std::atomic<uint64_t> g_frame_count{0};
Clock::time_point g_frame_start{};
} // namespace
// ---------------------------------------------------------------------------
// Hook: VdSetDisplayMode swap interval skip (0x821F0758)
// ---------------------------------------------------------------------------
bool ac6VsyncIntervalHook() {
return REXCVAR_GET(ac6_unlock_fps);
}
// ---------------------------------------------------------------------------
// Hook: Delta time divisor override (0x821EFD38)
// ---------------------------------------------------------------------------
void ac6DeltaDivisorHook(PPCRegister& r29) {
if (REXCVAR_GET(ac6_unlock_fps)) {
r29.u64 = 30;
}
}
// ---------------------------------------------------------------------------
// Hook: Frame timing stats (0x821F0664, before VdSwap call)
//
// Records timestamp at each present call to measure render-thread frame time.
// ---------------------------------------------------------------------------
void ac6PresentTimingHook() {
auto now = Clock::now();
if (g_frame_start.time_since_epoch().count() != 0) {
double ms =
std::chrono::duration<double, std::milli>(now - g_frame_start)
.count();
g_frame_time_ms.store(ms, std::memory_order_relaxed);
g_fps.store(ms > 0.0 ? 1000.0 / ms : 0.0, std::memory_order_relaxed);
g_frame_count.fetch_add(1, std::memory_order_relaxed);
}
g_frame_start = now;
}
namespace ac6 {
FrameStats GetFrameStats() {
return FrameStats{
g_frame_time_ms.load(std::memory_order_relaxed),
g_fps.load(std::memory_order_relaxed),
g_frame_count.load(std::memory_order_relaxed),
};
}
} // namespace ac6
+23
View File
@@ -0,0 +1,23 @@
/**
* @file render_hooks.h
* @brief Mid-asm hooks for vsync interval, frame timing, and 60fps unlock.
*/
#pragma once
#include <cstdint>
#include <rex/cvar.h>
REXCVAR_DECLARE(bool, ac6_unlock_fps);
namespace ac6 {
struct FrameStats {
double frame_time_ms;
double fps;
uint64_t frame_count;
};
FrameStats GetFrameStats();
} // namespace ac6