Roadmap: add the review findings as Current work

From an in-depth review pass: confirmed bugs, correctness/robustness items to
verify-then-fix, the D3D9/OpenGL present-thread readback perf fixes, cross-process
ABI hardening, test-coverage gaps, the static-CRT + Vulkan-layer-cleanup features,
three UX fixes, and stale-comment/VtableHook cleanup. Each lands test-first as its
own commit and is removed from this list when done.

Also drop the inaccurate completed-work-lives-in-Lessons-learned line -- done
tasks live in git history; Lessons learned is only for genuinely important
lessons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 01:04:12 +02:00
parent 0eb275daca
commit 3f1ce0c78a

View File

@@ -108,7 +108,79 @@ default** and covers anything the hooked path doesn't.
## Roadmap
Completed work lives in **Lessons learned** + the test suite, not here.
### Current work
From an in-depth review pass. Each item is fixed test-first (a failing test, then the fix) and lands
as its own commit; "verify" items are confirmed real before any change, and dropped if not.
Confirmed bugs:
- **Shutdown use-after-free of `ui`** — the ImGui settings handler holds `&ui`, but `~ImGuiLayer`'s
`DestroyContext` saves settings *after* `ui` (declared later in `run()`) is destroyed. Reorder /
remove the handler before teardown.
- **Host device loss unhandled** — `Present`/`ResizeBuffers`/`CreateRenderTargetView` HRESULTs are
ignored and a removed/reset device spins silently. Detect `DEVICE_REMOVED/RESET`, log
`GetDeviceRemovedReason`, surface it, and halt the render loop cleanly.
- **Keyed-mutex `WAIT_ABANDONED` not handled** — `shared_texture` treats it as "skip", so a mirror
never recovers after a host crash + reconnect. Treat it as acquired (copy + release).
Correctness (verify, then fix if real):
- **`vk_hook` / `vk_layer` `g_swaps`** — no synchronization on push/iterate and never pruned on
swapchain destroy (unbounded growth + stale-handle match). Add a guard + a `vkDestroySwapchainKHR`
prune.
- **`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
(the inline-readback pattern that caused the Vulkan 144→3 FPS stall), add a present-thread overhead
guard + dedicated test.
- **OpenGL capture readback off the present thread** — async PBO readback + off-thread swizzle/flip,
with an overhead guard.
Robustness (verify, then fix if real):
- **`mkb_forward` sticky mouse-up** — a held button isn't released when mirroring toggles off / ImGui
grabs the mouse. Release held buttons.
- **Swallowed audio loopback `start()` failures** — surface a process-loopback activation failure
distinctly from "no correlation" in the verifier + loopback.
- **Permissive injector bitness gate** — `IsWow64Process2` failure is treated as 64-bit; fall back to
`IsWow64Process` instead of mis-injecting.
- **Ignored HRESULT/BOOL returns** — `CreateShaderResourceView`, `GetClientRect`/`ClientToScreen`,
`XInputSetState`, `GetExitCodeProcess`: check and surface/handle.
Cross-process / ABI:
- **Tie `kProtocolVersion` to the layout** — `static_assert` `sizeof(SharedBlock)` + the full offset
set, and make `hook_selftest`'s `dump_layout` assert instead of only printing.
- **`log_ring` torn-text window** — verify the MPSC overwrite race; fix or bound it.
- **`narrow`/`widen` not inverse** — make the audio-override name round-trip lossless (or document).
Test coverage:
- **`log_ring`** — threaded push/drain + wrap-skip generation test (currently zero coverage).
- **Seqlock reader paths** — torn-read retry, odd-sequence skip, attempt-exhaustion → false.
- **Version/magic mismatch rejection** — negative test that the hook refuses a bad version.
- **Dedicated hook tests** — `focus_spoof`, `vk_hook` (present), `d3d9_hook`.
- **Misc units** — `SharedMemory` RAII/move, `wav` malformed input, `tool_paths` resolution, injector
bitness check; strengthen the `audio_ring` overrun-at-seam case.
Features:
- **Static CRT (`/MT`) for `coop_hook.dll`** (x64 + x86) so it loads in games without the VC++ redist.
- **Stale Vulkan-layer registration cleanup** — remove a leftover `HKCU` implicit-layer entry from a
crashed prior run on host startup.
UX:
- **Auto re-attach control** — keep it visible/controllable when not connected (today it can be
enabled-but-invisible).
- **Tooltips on disabled controls** — explain *why* Inject/subsystem controls are disabled.
- **Case-insensitive log filter.**
Code quality:
- **Stale comments** — `hook_guard.hpp` top block (still the old destroy-on-remove model),
`input_source.hpp` ("future" Steam source), `audio_ring.hpp` (v1/reserved), `shared_memory.hpp` /
`audio_ring.hpp` ("20-byte pads").
- **Consolidate `VtableHook`** — remove the duplicate copy in `audio_hook.cpp`.
### Future work