Deactivate frame-sync when the hooked target isn't alive

A game that used the Hooked source with "Sync flip to game frames" left
the overlay sluggish (~5 FPS) after it terminated or was detached: with no
live game the generation never bumps, so wait_for_hooked_frame waited out
its full timeout every iteration.

Gate frame_sync_active() on InjectionPanel::target_state() == Alive, so a
terminated/hung/detached target falls back to normal vsync. Alive means the
process is running and the hook heartbeat is advancing, so this also covers
a frozen game (which would stall the generation the same way). The checkbox
preference is preserved -- frame-sync auto-resumes when a new game is
injected rather than silently unchecking.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 20:18:29 +02:00
parent ffaad6c4ae
commit f15f5cdb36
2 changed files with 16 additions and 7 deletions

View File

@@ -57,6 +57,15 @@ void plot_multiseries(const char* id, const GraphSeries* series, int n_series, f
}
} // namespace
bool CapturePanel::frame_sync_active() const
{
// Only sync to the hook's frames while the target is actually alive and producing
// them. A terminated or hung game stops bumping the generation, so syncing would make
// every iteration wait out the timeout in wait_for_hooked_frame -- fall back to vsync.
const bool hook_alive = injection_ != nullptr && injection_->target_state() == TargetState::Alive;
return frame_sync_ && enabled_ && source_ == Source_Hooked && hook_alive;
}
bool CapturePanel::init(ID3D11Device* device)
{
device_ = device;

View File

@@ -58,13 +58,13 @@ public:
return source_ == Source_Hooked;
}
// True when the operator asked to pace the tool's flip to the game's published
// frames (only meaningful with the Hooked source while mirroring). The main loop
// reads this to wait for a new hook frame and present without vsync.
[[nodiscard]] bool frame_sync_active() const
{
return frame_sync_ && enabled_ && source_ == Source_Hooked;
}
// True when the operator asked to pace the tool's flip to the game's published frames
// (only meaningful with the Hooked source while mirroring) AND the target is alive and
// still producing them. The main loop reads this to wait for a new hook frame and
// present without vsync; gating on liveness stops a terminated/hung game from making
// every frame wait out the sync timeout (~5 FPS sluggish overlay). Defined in the .cpp
// since it needs the InjectionPanel definition for target liveness.
[[nodiscard]] bool frame_sync_active() const;
private:
enum Source : int