fix(vk): preserve pending screenshots before readback slot reuse #1519

Merged
Arkex-ai merged 1 commit from fix/capture-slot-ownership into main 2026-11-10 07:48:34 +00:00
Arkex-ai commented 2026-11-10 06:04:18 +00:00 (Migrated from github.com)

A delayed normal screenshot can remain pending until another shot reuses its parity-selected readback buffer. The newer GPU copy is submitted before the old capture is read; waiting for the old timeline value can then attach newer pixels to the older frame's filename and flash analysis.

Snapshot the pending pixels before recording another write into their slot, then move that CPU-owned snapshot into the existing consumer. Another slot keeps its asynchronous path, and no pending capture adds no wait. Re-arming clears the saved snapshot. Capture format, generated-shot handling and game rendering stay unchanged; there is no global wait-every-frame policy.

Validation at 88bfc18 on main 60b0c9b:

  • Execute the actual producer/read/consume statements with a queued GPU model across97sparse intervals, fast/late completion and no-pending controls. Original main fails the same-slot pixel/metadata check. Removing protection, moving it after submit, ignoring saved pixels or testing the wrong parity each restores an assertion failure.
  • Windows LLVM, Linux GCC and GCC ASan/UBSan pass. Full Windows suite217pass/3fail/22skip versus exact main216/3/22, with the same NUP privilege, legacy FPS include and native SDK limitations. No green full-suite claim.
  • Official matching API11 host/backend build passes. Native FG2 run with immediate made-shot mode disabled produced nine fully decoded normal RGB3440x1440 PNGs, exercised maximize/restore, and exited0; original save hashes unchanged. This is asynchronous-path compatibility, not a claim to reproduce GPU timing on hardware.

Host-cache visibility is separate in #1502. A private composition keeps its normal invalidation inside the new shot_pixels helper, after the wait and before copying; all six normal/generated/log coherent/noncoherent cases pass, including overwriting GPU bytes after the pending snapshot. Removing normal invalidation fails. This PR does not duplicate1502's changes. #1025's request path still needs the same ownership rule when integrated. See docs/capture-slot-ownership.md.

Exact-head fork workflows follow. No game data, screenshots, captures, generated C or binaries are included.

Current-head validation

Current head 675367e, based on main 7d1562d. Earlier local/runtime results describe their recorded source hashes.

The standalone contribution patch is unchanged after the audited main refresh; exact-head build/source checks are refreshed below. Earlier runtime evidence remains tied to its recorded hash.

Fork runs are separate from upstream Actions approval; no maintainer approval gate is bypassed.

A delayed normal screenshot can remain pending until another shot reuses its parity-selected readback buffer. The newer GPU copy is submitted before the old capture is read; waiting for the old timeline value can then attach newer pixels to the older frame's filename and flash analysis. Snapshot the pending pixels before recording another write into their slot, then move that CPU-owned snapshot into the existing consumer. Another slot keeps its asynchronous path, and no pending capture adds no wait. Re-arming clears the saved snapshot. Capture format, generated-shot handling and game rendering stay unchanged; there is no global wait-every-frame policy. Validation at `88bfc18` on main `60b0c9b`: - Execute the actual producer/read/consume statements with a queued GPU model across97sparse intervals, fast/late completion and no-pending controls. Original main fails the same-slot pixel/metadata check. Removing protection, moving it after submit, ignoring saved pixels or testing the wrong parity each restores an assertion failure. - Windows LLVM, Linux GCC and GCC ASan/UBSan pass. Full Windows suite217pass/3fail/22skip versus exact main216/3/22, with the same NUP privilege, legacy FPS include and native SDK limitations. No green full-suite claim. - Official matching API11 host/backend build passes. Native FG2 run with immediate made-shot mode disabled produced nine fully decoded normal RGB3440x1440 PNGs, exercised maximize/restore, and exited0; original save hashes unchanged. This is asynchronous-path compatibility, not a claim to reproduce GPU timing on hardware. Host-cache visibility is separate in #1502. A private composition keeps its normal invalidation inside the new `shot_pixels` helper, after the wait and before copying; all six normal/generated/log coherent/noncoherent cases pass, including overwriting GPU bytes after the pending snapshot. Removing normal invalidation fails. This PR does not duplicate1502's changes. #1025's request path still needs the same ownership rule when integrated. See `docs/capture-slot-ownership.md`. Exact-head fork workflows follow. No game data, screenshots, captures, generated C or binaries are included. <!-- goal15-current-validation --> ### Current-head validation Current head `675367e`, based on main `7d1562d`. Earlier local/runtime results describe their recorded source hashes. The standalone contribution patch is unchanged after the audited main refresh; exact-head build/source checks are refreshed below. Earlier runtime evidence remains tied to its recorded hash. - [Linux AppImage](https://github.com/Arkex-ai/Hookshot/actions/runs/42774784173): success. - [Windows builder](https://github.com/Arkex-ai/Hookshot/actions/runs/42774780796): success. - [Game-free source regressions](https://github.com/Arkex-ai/Hookshot/actions/runs/42774777662): success. Fork runs are separate from upstream Actions approval; no maintainer approval gate is bypassed.
Commenting is not possible because the repository is archived.
No description provided.