Run clang-format (the repo's .clang-format: LLVM base, 120 cols, tabs,
Allman functions) over every source file so the tree is formatter-clean.
Whitespace only -- no behavior change; full x64 + x86 suites pass.
Also set SortIncludes: false in .clang-format. Windows include order is
load-bearing (windows.h must precede tlhelp32.h / mmreg.h / xinput.h /
dinput.h; winsock2.h must precede windows.h), and the default
alphabetical sort reorders tlhelp32.h ahead of windows.h -- a build
break. Leaving order alone keeps the manual, correct grouping.
The capture must never change vsync, and must not frame-limit itself.
- Removed the ~150 Hz capture throttle from VkCapture. It was wrong: vsync already
paces capture (a 144 Hz FIFO game presents 144x/s, so we mirror 144x/s). The only
limiter left is ring backpressure (skip a frame if the reaper is behind), which is
correctness, not a cap, and never touches the game's present thread or sync mode.
- The layer/hook already pass VkSwapchainCreateInfoKHR straight through, so the
present mode (= the sync mode) is untouched. Added a presentMode log to prove it.
Measured on Sphere Spectacle (direct launch, layer attached): presentMode=2 (FIFO),
steady 144.0 fps, and with the throttle gone the mirror now tracks it at 144/s
(was capped ~130). The earlier 400-600 fps reading was a direct-launch artifact --
a non-foreground windowed FIFO app isn't throttled by DWM -- not the layer, and not
the case through Steam (144). vk_validate now states the mirror follows the present
rate (no throttle) and still asserts a present-rate floor.
Full suite 21/21.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The earlier validation concluded suspended-inject was "not applicable -- the
title requires launching through Steam." That was wrong; it was two bugs:
1. coop_vk_validate's inject mode launched the exe with CreateProcessW and a
null working directory, so the game couldn't load steam_api64.dll / resources/
(loaded relative to cwd) and never rendered -> no presents. Launch with the
game's own folder as cwd and it runs fine directly, no Steam needed.
2. The game resolves vkQueuePresentKHR / vkCreateSwapchainKHR via
vkGetInstanceProcAddr (volk's volkLoadInstance does this), but vk_hook only
substituted our detours when they were resolved via vkGetDeviceProcAddr -- so
the present bypassed the hook. Intercept those names in hk_vkGetInstanceProcAddr
too (our detours already gate on g_capture_enabled/g_device, so handing them out
before the device exists is safe).
With both fixed, inject mode captures Sphere Spectacle correctly: 1920x1080,
correct colors/orientation (screenshot), ~480 fps present while mirroring at the
~150 Hz throttle -- no present-thread impact (the VkCapture fix is shared).
Also makes the validator ASSERT a present-rate floor while capturing (it used to
report the rate and rationalize it, which is exactly what hid the 144->3 FPS
stall), and reports the true mirror rate from video.generation. Division of labor
is about who launches the game: layer for Steam-launched (can't suspend), inject
when we control the launch. README lessons-learned corrected accordingly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds coop_vk_validate, a harness that drives the Vulkan capture path end-to-end
against a shipping title (default Sphere Spectacle, a pure-Vulkan game) and asserts
frames reach the shared texture and advance, the captured resolution/colors are
sane, saves a BMP screenshot for visual confirmation, and reports the present rate.
Findings:
- Layer method WORKS: coop_vk_layer mirrors the game correctly at 1920x1080 --
right colors/brightness, no BGRA/RGBA swizzle, no sRGB darkening (screenshot
confirmed). The layer captures every present (no drops).
- Suspended-inject "Auto-attach" is NOT applicable to a Steam title that must launch
through Steam: its exe renders nothing when launched directly, so there's no Vulkan
present to catch. The layer is the method for Steam Vulkan games (the early-inject
mechanism itself is covered by mock_game_test's suspended-launch path).
- The layer does video, but the game needs coop_hook.dll co-injected for focus-spoof
or an unfocused, event-driven game throttles itself to a few fps (looks like a
capture slowdown but isn't). A present-rate number alone can't prove "no FPS impact"
-- it's the game's own cadence; capture stays off the critical path (every present
copied, read-back on its own queue + present-semaphore re-chain).
Also adds SharedTextureSource::read_frame (bulk RGBA readback) for the screenshot.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>