M2(Vulkan): too-late detection + red relaunch banner on the mirror window
The hook reports vk_too_late when vulkan-1.dll is loaded and the GPA hook has been in for >4s but it never caught the app creating its device -- i.e. the app resolved its Vulkan functions before we hooked (injected too late). Surfaced through a new HookStatus.vk_too_late field (protocol 15->16) and shown by the host as a red banner on the mirror window: "Detected a Vulkan game, but the mirror hook attached too late... enable Auto re-attach (and Set up Vulkan layer if it persists) and relaunch." WGC keeps mirroring meanwhile. mock_game_test gains a too-late detection check (late-inject a Vulkan game -> vk_too_late trips). Verified live: the banner shows over the running tool when a Vulkan game is injected late with the video subsystem on (added a debug-harness `video on/off` command to drive it). 15/15 ctest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -403,6 +403,57 @@ void test_vk_capture(ID3D11Device* device)
|
||||
cleanup();
|
||||
}
|
||||
|
||||
// Vulkan too-late detection: launch the vk mock normally (it inits Vulkan immediately), inject
|
||||
// *late* (the realistic case), and assert the hook reports vk_too_late -- it sees vulkan-1.dll
|
||||
// loaded but never caught the device, because the app resolved its present pointer first. This is
|
||||
// what drives the host's relaunch banner.
|
||||
void test_vk_too_late()
|
||||
{
|
||||
std::printf("== vk too-late detection (late inject) ==\n");
|
||||
MockGame game = MockGame::launch(L"vk 30");
|
||||
if (!game.ok)
|
||||
{
|
||||
check(false, "launch vk mock (too-late)");
|
||||
return;
|
||||
}
|
||||
Sleep(1200); // let it create its instance/device and start presenting
|
||||
if (!game.alive() && game.exit_code() == 2)
|
||||
{
|
||||
std::printf(" Vulkan unavailable on this machine -- skipping\n");
|
||||
game.kill();
|
||||
return;
|
||||
}
|
||||
SharedMemory shm;
|
||||
const std::uint32_t disabled = (1u << HookSubsys_Input) | (1u << HookSubsys_Focus) |
|
||||
(1u << HookSubsys_Audio) | (1u << HookSubsys_Mkb);
|
||||
SharedBlock* block = make_ipc(shm, game.pid(), disabled);
|
||||
if (block == nullptr || !inject_retry(game.pid()))
|
||||
{
|
||||
if (!game.alive() && game.exit_code() == 2)
|
||||
{
|
||||
std::printf(" Vulkan unavailable -- skipping\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
check(false, "inject vk mock (too-late)");
|
||||
}
|
||||
game.kill();
|
||||
return;
|
||||
}
|
||||
bool too_late = false;
|
||||
for (int i = 0; i < 160 && game.alive(); ++i) // ~8 s (past the hook's 4 s grace)
|
||||
{
|
||||
Sleep(50);
|
||||
if (block->status.vk_too_late != 0)
|
||||
{
|
||||
too_late = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
check(too_late, "hook reports vk_too_late after a late inject into a Vulkan game");
|
||||
game.kill();
|
||||
}
|
||||
|
||||
// Launch the mock game rendering audio at `rate`/`channels`/`bits`/`fmt`, inject the audio
|
||||
// hook (late, so it's the guessed path), and verify the hook MEASURES the right sample rate
|
||||
// for this variant and captures non-silent audio. (Channels/bit-depth aren't recoverable for
|
||||
@@ -628,6 +679,7 @@ int main()
|
||||
// Vulkan: present pointer cached at init -> can't be late-hooked, so we capture via the
|
||||
// early-load path (suspended launch + inject + resume; the mock loads Vulkan and waits).
|
||||
test_vk_capture(device);
|
||||
test_vk_too_late();
|
||||
test_video_capture("gl", device);
|
||||
test_video_capture("dx9ex", device);
|
||||
test_video_capture("dx9", device);
|
||||
|
||||
Reference in New Issue
Block a user