mirror of
https://github.com/sal063/AC6_recomp
synced 2026-08-14 20:44:00 -04:00
Add more rexcrt entries, add guest framerate counter
This commit is contained in:
@@ -14,6 +14,7 @@ include(generated/rexglue.cmake)
|
||||
# Sources
|
||||
set(AC6RECOMP_SOURCES
|
||||
src/main.cpp
|
||||
src/render_hooks.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
||||
@@ -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
@@ -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 {}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user