Repository navigation
perf(vk): a command buffer too short to split skips the dry pass - #2781
hckrman101 merged 1 commit into
Conversation
Assisted-by: oc-impl-2 (opencode/deepseek-v4.1-flash) Trace-Issue: NotRexed#2278
|
In-game A/B (short command buffers skip the parallel replay dry pass)
Path: "N short ones recorded here" 2329 per report with the patch (0 with the fallback), dry pass 0.22 -> 0.17 ms; segments per big command buffer unchanged (2.6-2.7). Replay CPU submit 4.84 -> 4.73 ms/frame (-2.3%), draw 3.69 -> 3.64, memory sync 1.29 -> 1.25. Costs: avg +1.5%, 1% low +4.7%, p99 -0.56 ms; the NO_DRY_SHORT=1 fallback lands within noise of control. No black-frame or exposure anomalies. Setup: RTX 5070 12 GB, i5-14600KF, Windows 11 26200, 1440p, frame generation on, 240 cap, RX_VK_PARALLEL=4 (owner env), same save/route, 2 clean runs per build, CPU idle checks. DLL-only on the installed v2.1.0 host (MKWVK API 14): the vk_replay change was ported onto the v2.1.0 tree, because an upstream-main build (51da046, API 19) cannot load into that host. |
Joey-Magnus
left a comment
There was a problem hiding this comment.
CI never ran on this head, so I merged it into current main and ran the whole tests/run_all.py with the Vulkan headers. 459 passed. The only failure is tests/test_lift_cache.py, which fails on main on this machine too. I traced the logic. The stream_work(h, 2 * per) < 2 * per test at vk_replay.cpp:1531 matches main's one-segment case: nseg is clamped from total / per, and stream_work counts the same ops as dry_work. NOP_JUMP and NOP_CALL do nothing in replay, so walking to NOP_END is linear and safe. The short path is the serial path players already run with parallel off. It fully replaces the old one-segment record_segment, and after a multi-segment buffer the next recording still starts with full_barrier. Turning off maybe_split matches main, where the one segment ran in Worker mode and wasn't split. The in-game A/B is on a v2.1.0 port, not this head, but the path is off by default, so that's acceptable. Heads-up: #2786 edits the same 240-buffer logf block, and the two conflict there.
Why
With parallel replay on (
RX_VK_PARALLEL), every command buffer first paid a dry pass - the whole stream applied for state only - and then its one segment was recorded on the replay thread anyway: the same stream walked twice for nothing. A submission of a few hundred draws is one segment, and on a title that submits six a frame that was most of them. This removes that second walk for those short command buffers, a recording cost on the CPU side of the replay path.Issue: #2278 - FPS Drops to 25-30 In-Game but Reaches 60 FPS in Menu (#2278). The report is collected in #995; this change addresses the replay path's share of it, with the measurement still to come.
The default path is untouched: with
RX_VK_PARALLELoff (the default), every command buffer is recorded exactly as before. This change only affects players who turned parallel replay on.What changed
gpu/vk/vk_replay.cpp:op_is_workis the draw/dispatch test the dry pass already counteddry_workwith, now shared.stream_workcounts a stream's draws and dispatches from its op headers without applying anything, stopping at the count asked.replay_handlecounts the stream before the dry pass. When it holds fewer than two segments (2 * RX_VK_PARALLEL_SEG, default 320 draws and dispatches), it records the command buffer once on the replay thread, as parallel replay off does, and skips the dry pass.RX_VK_NO_DRY_SHORT=1brings the old behavior back.split_off(thread-local) keepsmaybe_splitfrom chunking that recording: a segment is not split.tests/test_parallel_small_cb.py(new): checks the source wiring (the op test, the count before the dry pass, the serial recording, the switch,maybe_split) and compilesstream_workagainst a byte stream: counts draws and dispatches, stops at the count asked, ignores ops pastNOP_END, and returns 0 for a state-only stream.Testing
Game-free, Windows, llvm-mingw, in the worktree:
python -I -B tests/run_all.py: 462 passed, 1 failed, 33 skipped.tests/test_input_background.py, a known environment failure declared in this repo's config on this PC (no MSVC SDK); it fails the same way on an untouched upstream main, proven with clang 23.1.5 (-Wunused-but-set-global).tests/test_precompile_compute_guard.pyandtests/test_recorder_sync.py, passed in this run.test_parallel_small_cbpasses. The verification run also showed the new check fails on upstreamee29dd55for the missingstream_work/op_is_workwiring and passes on the branch head.GPU/driver/area: NVIDIA GeForce RTX 5070 12 GB, driver 32.0.16.2114 (Vulkan 1.4), Windows 11 build 26200, i5-14600KF. Zone: Vulkan command-buffer replay (
gpu/vk/vk_replay.cpp), theRX_VK_PARALLEL=1path only.in-game A/B: pending, results will be added in a comment
AI assistance
Assisted-by: oc-impl-2 (opencode/deepseek-v4.1-flash), oc-upstream-1 (opencode/deepseek-v4.1-flash-free)