diff --git a/README.md b/README.md index ef90e31..21e5bc5 100644 --- a/README.md +++ b/README.md @@ -114,12 +114,8 @@ From an in-depth review pass. Each item is fixed test-first (a failing test, the as its own commit; "verify" items are confirmed real before any change, and dropped if not. Correctness (verify, then fix if real): -- **`mkb_hook` raw-input slot reuse** — a 64-slot ring can overwrite an event before the game reads - the `WM_INPUT`. Verify; fix if real. - **Non-atomic cross-process diagnostic counters** — `present_calls`, `frames_dropped`, `frames_rendered` are plain `+=`/stores read by the host. Make them atomic. -- **`publish()` synthetic-input timing** — confirm it doesn't read ImGui/UI state from the input - thread; fix if so. Performance (failing perf-regression test first): - **D3D9 capture readback off the present thread** — move the swizzle/flip to an off-thread reaper diff --git a/hook/src/mkb_hook.cpp b/hook/src/mkb_hook.cpp index cdc9334..9203b30 100644 --- a/hook/src/mkb_hook.cpp +++ b/hook/src/mkb_hook.cpp @@ -63,7 +63,15 @@ std::atomic g_di_mouse_primed{false}; // of a synthetic RAWINPUT slot, and this hook serves that slot's data when the game reads it back. safetyhook::InlineHook g_hk_getrawinputdata; // user32!GetRawInputData int g_id_rawinput = -1; -constexpr int kRawSlots = 64; // small ring of synthetic events (games consume WM_INPUT promptly) +// Ring of synthetic RAWINPUT events. Each posted WM_INPUT carries the ADDRESS of its slot, and the +// game reads it back through hk_GetRawInputData. The slot must not be overwritten between the post and +// that read, or the game decodes a newer event for a stale message. A game's message loop drains +// WM_INPUT promptly (one per dispatch), so overwrite only happens if more than kRawSlots events queue +// up before the game pumps -- e.g. a burst during a stall. We size the ring generously rather than +// track per-slot consumption: consumption tracking would permanently exhaust slots (and silently stop +// forwarding) for a game that ignores WM_INPUT, whereas a large ring always forwards and only risks a +// rare stale read under extreme backlog. ~512 * sizeof(RAWINPUT) is a few tens of KB. +constexpr int kRawSlots = 512; RAWINPUT g_raw_slots[kRawSlots] = {}; std::atomic g_raw_head{0};