Skip to content

perf(agc): bypass the draw cache while its hit rate is under 5% - #12478

Closed
EagleBearerYS wants to merge 13 commits into
boykopovar:mainfrom
EagleBearerYS:perf/agc-draw-cache-low-hit-bypass-main
Closed

EagleBearerYS wants to merge 13 commits into
boykopovar:mainfrom
EagleBearerYS:perf/agc-draw-cache-low-hit-bypass-main

Conversation

@EagleBearerYS

@EagleBearerYS EagleBearerYS commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

What

Based on @bcortezf's #5404, which they closed on 2026-10-22. This is their bypass on current main, with their co-authorship in the commit.

When two windows of 2,048 draw-cache lookups in a row each have fewer than 5% useful lookups, the next 2,048 draws neither look up nor insert draw entries. Each further low window in a row doubles that, up to 16,384, and a window at or above 5% ends the run. A lookup counts as useful when the whole draw hits, when a cached draw of the same shape is found (before its data and push-offset checks decide whether a stage is reused), or when its draw key was seen before, since the cache admits the draw at that sighting.

  • APS5_DRAW_CACHE_BYPASS_PERCENT sets the threshold (default 5). 0 never bypasses, and values above 100 count as 100. Its row is in ENVIRONMENT.md.
  • With APS5_PROFILE_DRAW, [draw-cache] bypassed N draws (10 s): useful lookups stayed under 5% for two or more windows in a row reports how many draws skipped the cache. The bypass counts them in an atomic, so a bypassed draw takes no lock.
  • The bypassed draws take the path useDrawEntries == false already takes (the same as APS5_NO_DRAW_SRT_ENTRIES), so no new draw path is added.

On @oneandonlydean's review of #5404 (comment):

  • Stage hits now count (ab71996). useDrawEntries still gates stageEntries, so a bypassed draw also skips stage reuse. But the window now counts a lookup as useful when the whole draw hits, or when a cached draw of the same shape is found for one of its stages (the data-only path), before the data and push-offset checks decide whether that stage is reused. So a scene whose whole-draw keys miss while its stages hit keeps the cache, as you suggested.

    On Resident Evil Village (PPSA01556)'s main menu, stage reuse was small anyway. These are the [draw-cache] lines of two profiled runs of the same menu on a local tree without the bypass, at menu +15 min:

    • with the 256 MiB budget, 0 whole-draw hits and 0 stage validations in about 3,000 lookups per 10 s;
    • with the budget off, 88 to 115 whole-draw hits per 10 s (about 4%), and 176 to 230 of 424 to 512 stage validations equal.
  • One window word (ab71996). The window's hits and lookups are now one 64-bit word updated by a single compare-exchange, so exactly one caller closes each window.

  • The exact threshold (b7001db). The minimum is ceil(2048 × percent / 100), 103 hits at 5%. So 102 hits in 2,048 lookups (4.98%) bypasses and 103 keeps the cache, matching "fewer than 5%".

  • Speed at main's defaults (the 256 MiB budget from fix(agc): bound the draw cache by bytes #9129 on, the bypass at 5%): this description claims no speed gain for the current head.

    • Before the warm-up fix below, a8e7e2f ran Resident Evil Village (PPSA01556)'s menu 26% faster than main 319621b, and saved no memory (Tested).
    • On 14209e9, with the warm-up fix, a pair on main ebb4075 shows no measurable gain (Tested).
    • On 1679477, a pair on main 6472c70 ran 13.3% faster. But in a profiled boot of that tree the bypass starts in none of the measured window's 57 ten-second blocks, so that gain isn't attributed to this change (Tested).
    • Why it doesn't start at that menu: every lookup there finds no entry, so a window's useful lookups can only be sightings of draw keys seen before, which the warm-up rule counts. They keep each window above 5%. The 3.8 GB saving in the older pair below was measured with the budget off.

On @adriadam10's review and @bcortezf's warm-up report (review, report):

  • Warm-up (c7981bc). With second-sight admission a draw hits only at its third sighting. So on a cold scene of about 1,000 or more draws, the first window had almost no hits and started a bypass, during which no sightings were recorded either. Both suggested fixes are in:
    • a lookup whose draw key DrawKeySightings has seen before now counts as useful;
    • the bypass needs two low windows in a row. It starts at 2,048 draws and doubles with each further low window, up to 16,384.
    • Draws whose keys never repeat still reach the 16,384-draw bypass after a few windows.
  • No lock on the bypass path (40973d3). DrawCacheBypass counts the draws it skips in an atomic, and the draw-cache report takes and resets that count.
  • What the window counts is spelled out above and in the ENVIRONMENT.md row.
  • Base: 14209e9 merges main ebb4075. The draw-cache tests ran again on it (Tested), and the Village pair on the new base is in Tested.

On @MarcZX10's review of 14209e9 (review):

  • Window results apply in window order (11e29b3).
    • A window closed with one compare-exchange, but its low-window streak was set afterwards with a separate load and store. So a closer preempted in between could overwrite the reset of a useful window closed after it.
    • The window's lookups and useful lookups, the streak and the draws left to bypass now share one 64-bit atomic. The compare-exchange that closes a window also sets its streak and the bypass it starts, and Skip takes its draw from the same word.
    • The policy is unchanged: the existing cases pass unchanged.
  • Base: 05d2faa merges main 76fd1c0, and the draw-cache tests and the validation comparison ran on it (Tested).

Overlap: tools/pr_overlap.py finds no conflict with any open pull request that merges cleanly with main.

Related: #5404, #9129

Profiled boot of 14209e9 on Resident Evil Village (PPSA01556)'s menu (profiled, not a timing run). It ran under the warm-up fix's rule, where a lookup whose key was seen before counts as useful.

  • Setup: APS5_PROFILE_DRAW=1 with the usual APS5_LAZY_SHADER_PREPARE=1 APS5_NO_GPL=1 APS5_HOST_IMPORT_MIB=6400 APS5_TRACE_SUMMARY_EVERY=10 and the pad script, and no draw-cache variables. RTX 3070 Laptop GPU (NVIDIA 617.42), held 12 min past the menu.
  • Bypass: 9 [draw-cache] bypassed lines in 80 ten-second blocks, 112,640 draws bypassed in all (2,048, 4,096, 8,192, then 16,384 six times). All 9 are in the 8th to 18th blocks, none after.
  • Lookups: 331,056 of 331,072 found no entry, with 2 hits, and the byte budget evicted 33,539 entries.
  • Next: a pair on a variant where a second sighting of a key the budget evicted no longer counts as useful, with the cold-scene case still green. Its result goes into Tested.

The pairs, the captures, the profiled bypassed lines and the light-title run are in Tested.

Tested

  • Tests: agc_driver_draw_cache_low_hit_bypass (default) and agc_driver_draw_cache_low_hit_bypass_off (APS5_DRAW_CACHE_BYPASS_PERCENT=0) run four new cases in DrawCacheReuse.cpp, and agc_driver_draw_cache_cold_scene and its _off run a fifth. The draw-level cases draw only the lookups whose outcome they check and note the rest of each 2,048-lookup window on the driver's bypass (1679477, below).

    • LowHitRateBypassesTheCache checks that:
      • a window with 103 useful lookups in 2,048 (102 hits and the second sighting that admits a key) keeps the cache, and so does a single window of 102;
      • after two windows of 102 in a row, the next draws are neither looked up nor inserted, and a draw whose pixel constant changed still writes the new colour;
      • the driver's bypass then has 2,046 of its 2,048 draws left, and the draw after them looks up and hits its cached entry;
      • with the bypass off, the same draws are looked up.
    • StageHitsKeepTheCacheLookedUp: after one low window, a window whose only useful lookups are 103 draws whose keys miss but whose vertex stages are reused from the cache keeps the next draw looked up.
    • ConcurrentNotesCloseEachWindowOnce:
      • four threads noting only hits never close a window short;
      • one window of misses then starts no bypass, and a second bypasses exactly 2,048 draws;
      • four threads draining the next bypass skip 4,096 draws, and the bypass's count returns all 6,144 once.
    • LowWindowsLengthenTheBypass: a run of low windows bypasses 2,048, 4,096, 8,192 and then 16,384 draws. A window at 5% ends the run, and the next bypass again waits for two low windows and starts at 2,048. No draw is bypassed before the window that starts the bypass has closed.
    • ConcurrentClosesKeepTheirOrder: a low window closes on one thread while three others note the next, useful window, 256 times. The bypass the two low windows started must be exactly 2,048 draws, one more low window must start none, and a second must start 2,048.
    • ColdSceneKeepsTheCacheLookedUp (--cold-scene): a scene of 1,000 new draws, repeated every frame from cold, hits at least 90% by its fourth frame, with the bypass on and off.
    • Each commit's new cases, red on its parent (Linux, Ubuntu 24.04, GCC 13.3, Release; ^agc_driver_draw_cache ×10 at each commit, 13 tests, 130 of 130 runs, 0 skipped):
      • ab71996's two cases fail on 3e4d8e2;
      • b7001db's 102-against-103 case fails on ab71996 ("draws after a window of 102 hits in 2048 lookups were still looked up or inserted").
    • GitHub, red/green on main 04fefeb, ×10, for the first commit: on Linux the new case fails with main's code and passes 10 of 10 with this change (13 tests, 0 skipped), and the libc and libkernel suites run with 0 failed (run). On Windows all 13 build and skip, and the suites run with 0 failed.
    • c7981bc's cold-scene case, red on the head before it:
      • With the case added unchanged to 58171b2, agc_driver_draw_cache_cold_scene fails on Linux and its _off arm passes (run). On Windows both skip, since the runner has no Vulkan device.
      • 40973d3's count check uses the TakeBypassed that commit adds, so it doesn't build on its parent.
      • 11e29b3's ConcurrentClosesKeepTheirOrder passes on both 11e29b3 and its parent. The old code's gap can't be forced through the API without a hook in production code. Every existing case passes unchanged on 11e29b3, which shows the single-threaded policy is the same.
    • GitHub ×10 on a8e7e2f, a merge of main 319621b (clean; the PR's patch-id is unchanged) (run):
      • Linux: 13 run, 13 pass, 0 skip.
      • Windows: 13 skip, since the runner has no Vulkan device.
      • With APS5_SKIP_TIMING_TESTS=1, the libc and libkernel suites run 171 and 291 tests on Linux and 199 and 314 on Windows, with 0 failed.
    • Windows on an RTX 3070 Laptop GPU, for the first commit, on the pair's tree (the same code, 7bc49ce): both pass, in 24.3 s and 5.6 s. The GitHub Windows runner skips them, as it has no Vulkan device.
  • check_conventions.py passes, with no comment lines added.

  • Validation comparison (VERIFY_VALIDATION=1 on GitHub's Linux runner, llvmpipe (LLVM 20.1.2, Mesa 25.2.8), the two bypass tests and every ^agc_driver_draw_cache test):

    • a8e7e2f's tree (7157a5bf59, main 319621b against it): 13 passed, 0 skipped. VUID-VkDeviceCreateInfo-pNext-pNext appears in both arms, and the change adds none (run).
    • The first commit (main 04fefeb against 3e4d8e2): the same result (run).
    • Windows: the GitHub runner skips the tests, as it has no Vulkan device.
  • Resident Evil Village (PPSA01556), draw cache at main's defaults, static main menu, on a8e7e2f (before the warm-up fix). 16 min each run after a warm-up past the menu, unprofiled, B A A B, 2026-10-28.

    B: this head A: main
    presents over menu +5 to +15 min (fps) 543 (0.905) / 496 (0.827) 445 (0.742) / 381 (0.635)
    frame p50 / p90 1.1 / 1.1 s and 1.2 / 1.3 s 1.3 / 1.5 s and 1.5 / 1.9 s
    private bytes at menu +15 min 14,111 / 14,197 MB 13,972 / 14,445 MB
    Driver.Packet ms per frame 3,006 / 3,444 3,768 / 4,347
    Driver.Packet.memory_wait ms per frame 1,733 / 2,000 2,192 / 2,425
    Driver.Draw ms per frame 784 / 906 995 / 1,028
    • Speed: B's mean is 0.866 fps against A's 0.688 (+26%), and B is ahead in both adjacent pairs (0.905 vs 0.742, then 0.827 vs 0.635).

    • Memory: no difference. B is 55 MB lower on the mean, inside A's own 473 MB spread.

    • [draw-cache] lines at this menu, from one profiled B boot (APS5_PROFILE_DRAW=1 added, to menu +10; not a timing run):

      • bypassed 16384 draws (10 s) in 23 of the 25 ten-second blocks, 376,832 draws in all, from the second block on.
      • Between bypasses, the windows that stay looked up counted 54,859 lookups with 0 hits (all "no entry", no stage data hits) and 3,384 inserts.
      • The cache still filled to its budget: 432 entries, ~255.5 MiB of 256.0 MiB, with 2,952 evictions by the byte budget.
    • Captures, as the Performance report form describes: one traced run per arm on the same trees and caches as the pair, A then B in one session on 2026-10-28 (PT).

      • Environment: APS5_LAZY_SHADER_PREPARE=1 APS5_NO_GPL=1 APS5_HOST_IMPORT_MIB=6400 APS5_TRACE_SECONDS=960:30 and the pad replay (APS5_PAD_INPUT_FILE), with no other APS5_TRACE_* or APS5_PROFILE_* switch. Each arm wrote its trace and summary line into its own working directory.
      • The 30 s window opens 960 s after the title's first present, at about menu +10 min in both. Neither trace dropped events.
      • GPU clocks weren't held: A ran 97% of the 250 ms samples in P0, and B 88% in P0 and 10% in P5. The mean graphics clock was 1,356 MHz in A and 1,351 MHz in B.
      • B against A over the window:
        • 24 presents against 19; frame p50 1,264 against 1,510 ms (-16%), p90 1,638 against 1,868 ms (-12%), p99 1,664 against 2,204 ms (-25%);
        • Driver.Packet 3,666 against 4,499 ms per frame (-19%), of which memory_wait 2,133 against 2,668 and Packet.draw 970 against 1,217;
        • Packet.dispatch 526 against 565 ms, and GPU busy per present 244 against 232 ms.
      • These replace two captures from earlier on 2026-10-28 that also set APS5_TRACE_SUMMARY_EVERY=10 and APS5_TRACE_DIR, which the form doesn't allow. In those, B was also ahead (p50 1,080 against 1,178 ms), and Packet.dispatch was higher in B (564 against 492 ms).
      • The traces: A aps5-trace-103015a9ca66-13244.json.gz (2.4 MB) and B aps5-trace-bd421aa3c2fb-33348.json.gz (2.7 MB).
      • The summary lines, as aps5-summary.jsonl holds them (A, then B):
      {"commit":"103015a9ca66","dirty":false,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":3194,"ms":30115.819},"presents":19,"frame_ms":{"p50":1509.629,"p90":1868.179,"p99":2204.493,"max":2204.493},"gpu_busy_ms_per_present":232.162,"worker_busy_pct":{"queue worker 0x0":99.534,"queue worker 0x38":0.095,"queue worker 0x20":90.176,"queue worker 0x28":94.220},"top_phases_ms_per_frame":{"Driver.Packet":4498.822,"Driver.Packet.memory_wait":2667.696,"Driver.Packet.draw":1216.779,"Driver.Draw":1215.543,"Graphics.Draw":987.323,"Graphics.Draw.draw_and_resource_release":964.399,"Driver.Packet.dispatch":565.069,"Driver.Dispatch":523.953},"trace_dropped":false,"trace":"aps5-trace-103015a9ca66-13244.json.gz"}
      {"commit":"bd421aa3c2fb","dirty":false,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":3346,"ms":31244.555},"presents":24,"frame_ms":{"p50":1264.279,"p90":1637.960,"p99":1663.592,"max":1663.592},"gpu_busy_ms_per_present":244.214,"worker_busy_pct":{"queue worker 0x0":99.499,"queue worker 0x38":0.064,"queue worker 0x20":88.775,"queue worker 0x28":93.574},"top_phases_ms_per_frame":{"Driver.Packet":3666.451,"Driver.Packet.memory_wait":2132.717,"Driver.Packet.draw":969.522,"Driver.Draw":968.475,"Graphics.Draw":859.305,"Graphics.Draw.draw_and_resource_release":840.225,"Driver.Packet.dispatch":525.755,"Driver.Dispatch":483.792},"trace_dropped":false,"trace":"aps5-trace-bd421aa3c2fb-33348.json.gz"}
    A (main 319621b + fix(shader): load and store 16-bit data of converted packed images #11580 + fix(agc): keep buffer owners when a staged address space dissolves #10304): trace_digest.py

    seconds 960:30 from present 3194: 19 presents, frame p50 1509.6 / p90 1868.2 / p99 2204.5 / max 2204.5 ms, GPU busy 232.2 ms per present
    NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 3840x2160, commit 103015a, dropped: no

    {"commit":"103015a9ca66","dirty":false,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":3194,"ms":30115.819},"presents":19,"frame_ms":{"p50":1509.629,"p90":1868.179,"p99":2204.493,"max":2204.493},"gpu_busy_ms_per_present":232.162,"worker_busy_pct":{"queue worker 0x0":99.534,"queue worker 0x38":0.095,"queue worker 0x20":90.176,"queue worker 0x28":94.22},"top_phases_ms_per_frame":{"Driver.Packet":4498.822,"Driver.Packet.memory_wait":2667.696,"Driver.Packet.draw":1216.779,"Driver.Draw":1215.543,"Graphics.Draw":987.323,"Graphics.Draw.draw_and_resource_release":964.399,"Driver.Packet.dispatch":565.069,"Driver.Dispatch":523.953},"trace_dropped":false,"trace":"aps5-trace-103015a9ca66-13244.json.gz"}

    Slowest frames (largest slices inside each, inclusive)

    • present 3200: 2204.5 ms at 9605 ms: Driver.WorkerWait (queue worker 0x38) 2200.6, Driver.WorkerWait.dequeue_order (queue worker 0x38) 2193.2, Driver.Packet (queue worker 0x0) 2182.2, Driver.Packet (queue worker 0x28) 2112.9
    • present 3208: 1868.2 ms at 22628 ms: Driver.WorkerWait (queue worker 0x38) 1866.8, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1860.4, Driver.Packet (queue worker 0x0) 1849.5, Driver.Packet (queue worker 0x28) 1791.4
    • present 3204: 1851.0 ms at 16043 ms: Driver.WorkerWait (queue worker 0x38) 1848.2, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1841.8, Driver.Packet (queue worker 0x0) 1830.7, Driver.Packet (queue worker 0x28) 1764.5
    • present 3197: 1840.2 ms at 4500 ms: Driver.WorkerWait (queue worker 0x38) 1838.7, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1832.2, Driver.Packet (queue worker 0x0) 1819.8, Driver.Packet (queue worker 0x28) 1752.8
    • present 3205: 1778.4 ms at 17894 ms: Driver.WorkerWait (queue worker 0x38) 1775.8, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1767.7, Driver.Packet (queue worker 0x0) 1759.7, Driver.Packet (queue worker 0x28) 1690.9

    Threads (ms per frame)

    thread busy wait untraced in slices < 20 us largest
    queue worker 0x0 1119.8 (71 %) 451.8 (29 %) 13.4 88.6 Driver.Packet 1567.0
    draw committer 704.4 (44 %) 31.7 (2 %) 849.0 4.5 Graphics.Draw 719.1, Recorder.Submit 2.2
    presenter 3.6 (0 %) 0.2 (0 %) 1581.3 0.1 VideoOut.Flip 3.7, Driver.Present 0.1
    queue worker 0x38 1.2 (0 %) 1429.1 (90 %) 154.7 0.7 Driver.Packet 1.3, Driver.EndSubmission 0.1
    queue worker 0x20 132.0 (8 %) 1444.1 (91 %) 9.0 4.8 Driver.Packet 1426.2, Driver.EndSubmission 2.4
    queue worker 0x28 18.9 (1 %) 1553.9 (98 %) 12.3 0.2 Driver.Packet 1492.9, Driver.EndSubmission 0.5
    gpu 244.9 (15 %) 0.0 (0 %) 1340.2 0.0 batch 244.9

    Largest slices (ms per frame, inclusive, all threads): Driver.Packet 4487.4, Driver.Packet.memory_wait 2667.5, Driver.WorkerWait 1659.9, Driver.WorkerWait.dequeue_order 1423.1, Driver.Packet.draw 1215.9, Driver.Draw 1214.6, Graphics.Draw 986.8, Graphics.Draw.draw_and_resource_release 963.7, Driver.Packet.dispatch 564.2, Driver.Dispatch 523.0

    Longest waits

    • Driver.WorkerWait (queue worker 0x38) 2200.4 ms at 9609 ms, present 3200
    • Driver.Packet.memory_wait (queue worker 0x28) 1939.0 ms at 9765 ms, present 3200
    • Driver.WorkerWait (queue worker 0x38) 1866.8 ms at 22630 ms, present 3208
    • Driver.WorkerWait (queue worker 0x38) 1848.2 ms at 16046 ms, present 3204
    • Driver.WorkerWait (queue worker 0x38) 1838.9 ms at 4502 ms, present 3197
    • Driver.WorkerWait (queue worker 0x38) 1775.8 ms at 17897 ms, present 3205
    • Driver.WorkerWait (queue worker 0x38) 1755.1 ms at 7850 ms, present 3199
    • Driver.Packet.memory_wait (queue worker 0x20) 1708.3 ms at 9724 ms, present 3200
    • Driver.Packet.memory_wait (queue worker 0x28) 1625.6 ms at 22781 ms, present 3208
    • Driver.Packet.memory_wait (queue worker 0x28) 1605.6 ms at 4632 ms, present 3197

    Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)

    • batch 251: 41.9 ms at 6476 ms, present 3198: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.5, Driver.Packet.dispatch (queue worker 0x0) 0.5, Driver.Dispatch (queue worker 0x0) 0.4, Driver.Packet.flush_between_packets (queue worker 0x0) 0.1
    • batch 622: 41.6 ms at 16211 ms, present 3204: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 2.4, Driver.Packet.dispatch (queue worker 0x0) 2.1, Driver.Dispatch (queue worker 0x0) 2.0, Vulkan.DispatchRecipe (queue worker 0x0) 0.9
    • batch 1048: 41.6 ms at 27452 ms, present 3211: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 3.3, Driver.Packet.dispatch (queue worker 0x0) 3.0, Driver.Dispatch (queue worker 0x0) 2.9, Vulkan.DispatchRecipe (queue worker 0x0) 1.4
    • batch 744: 41.6 ms at 19805 ms, present 3206: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.7, Driver.Packet.dispatch (queue worker 0x0) 0.6, Driver.Dispatch (queue worker 0x0) 0.6, Vulkan.DispatchRecipe (queue worker 0x0) 0.1
    • batch 441: 41.6 ms at 11965 ms, present 3201: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 2.0, Driver.Packet.dispatch (queue worker 0x0) 1.8, Driver.Dispatch (queue worker 0x0) 1.7, Driver.Dispatch.lookup_cache (queue worker 0x0) 0.2
    B (this head + fix(shader): load and store 16-bit data of converted packed images #11580 + fix(agc): keep buffer owners when a staged address space dissolves #10304): trace_digest.py

    seconds 960:30 from present 3346: 24 presents, frame p50 1264.3 / p90 1638.0 / p99 1663.6 / max 1663.6 ms, GPU busy 244.2 ms per present
    NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 3840x2160, commit bd421aa, dropped: no

    {"commit":"bd421aa3c2fb","dirty":false,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":3346,"ms":31244.555},"presents":24,"frame_ms":{"p50":1264.279,"p90":1637.96,"p99":1663.592,"max":1663.592},"gpu_busy_ms_per_present":244.214,"worker_busy_pct":{"queue worker 0x0":99.499,"queue worker 0x38":0.064,"queue worker 0x20":88.775,"queue worker 0x28":93.574},"top_phases_ms_per_frame":{"Driver.Packet":3666.451,"Driver.Packet.memory_wait":2132.717,"Driver.Packet.draw":969.522,"Driver.Draw":968.475,"Graphics.Draw":859.305,"Graphics.Draw.draw_and_resource_release":840.225,"Driver.Packet.dispatch":525.755,"Driver.Dispatch":483.792},"trace_dropped":false,"trace":"aps5-trace-bd421aa3c2fb-33348.json.gz"}

    Slowest frames (largest slices inside each, inclusive)

    • present 3354: 1663.6 ms at 10085 ms: Driver.WorkerWait (queue worker 0x38) 1662.7, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1657.7, Driver.Packet (queue worker 0x0) 1646.1, Driver.Packet (queue worker 0x28) 1579.5
    • present 3362: 1662.1 ms at 20923 ms: Driver.WorkerWait (queue worker 0x38) 1661.5, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1655.5, Driver.Packet (queue worker 0x0) 1643.4, Driver.Packet (queue worker 0x28) 1562.6
    • present 3357: 1638.0 ms at 14491 ms: Driver.WorkerWait (queue worker 0x38) 1637.4, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1632.5, Driver.Packet (queue worker 0x0) 1621.5, Driver.Packet (queue worker 0x28) 1519.4
    • present 3346: 1491.3 ms at 0 ms: Driver.Packet (queue worker 0x0) 1467.4, Driver.Packet (queue worker 0x20) 1330.1, Driver.Packet (queue worker 0x28) 1293.5, Driver.Packet.memory_wait (queue worker 0x28) 1277.6
    • present 3355: 1460.3 ms at 11749 ms: Driver.WorkerWait (queue worker 0x38) 1459.3, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1453.0, Driver.Packet (queue worker 0x0) 1442.5, Driver.Packet (queue worker 0x28) 1381.2

    Threads (ms per frame)

    thread busy wait untraced in slices < 20 us largest
    queue worker 0x0 886.1 (68 %) 403.4 (31 %) 12.4 91.5 Driver.Packet 1285.5
    draw committer 613.3 (47 %) 34.5 (3 %) 654.1 5.3 Graphics.Draw 628.1, Recorder.Submit 1.8
    presenter 3.4 (0 %) 0.3 (0 %) 1298.1 0.1 VideoOut.Flip 3.5, Driver.Present 0.3
    queue worker 0x38 0.7 (0 %) 1183.7 (91 %) 117.5 0.9 Driver.Packet 0.6, Driver.EndSubmission 0.1
    queue worker 0x20 118.1 (9 %) 1176.9 (90 %) 6.9 4.9 Driver.Packet 1152.0, Driver.EndSubmission 3.1
    queue worker 0x28 17.9 (1 %) 1276.2 (98 %) 7.8 0.2 Driver.Packet 1217.7, Driver.EndSubmission 0.4
    gpu 244.4 (19 %) 0.0 (0 %) 1057.5 0.0 batch 244.4

    Largest slices (ms per frame, inclusive, all threads): Driver.Packet 3655.9, Driver.Packet.memory_wait 2132.6, Driver.WorkerWait 1403.0, Driver.WorkerWait.dequeue_order 1178.5, Driver.Packet.draw 968.5, Driver.Draw 967.4, Graphics.Draw 858.5, Graphics.Draw.draw_and_resource_release 839.2, Driver.Packet.dispatch 524.4, Driver.Dispatch 482.3

    Longest waits

    • Driver.WorkerWait (queue worker 0x38) 1662.1 ms at 10087 ms, present 3354
    • Driver.WorkerWait (queue worker 0x38) 1661.9 ms at 20924 ms, present 3362
    • Driver.WorkerWait (queue worker 0x38) 1637.0 ms at 14492 ms, present 3357
    • Driver.WorkerWait (queue worker 0x38) 1459.5 ms at 11750 ms, present 3355
    • Driver.WorkerWait (queue worker 0x38) 1449.6 ms at 26190 ms, present 3366
    • Driver.Packet.memory_wait (queue worker 0x28) 1440.4 ms at 10208 ms, present 3354
    • Driver.Packet.memory_wait (queue worker 0x28) 1437.2 ms at 21032 ms, present 3362
    • Driver.WorkerWait (queue worker 0x38) 1398.8 ms at 16130 ms, present 3358
    • Driver.Packet.memory_wait (queue worker 0x28) 1392.2 ms at 14602 ms, present 3357
    • Driver.WorkerWait (queue worker 0x38) 1280.7 ms at 13211 ms, present 3356

    Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)

    • batch 655: 41.7 ms at 14605 ms, present 3357: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 1.5, Driver.Packet.dispatch (queue worker 0x0) 1.3, Driver.Dispatch (queue worker 0x0) 1.3, Vulkan.DispatchRecipe (queue worker 0x0) 0.4
    • batch 184: 41.6 ms at 4148 ms, present 3349: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.3, Driver.Packet.dispatch (queue worker 0x0) 0.2, Driver.Dispatch (queue worker 0x0) 0.2, Vulkan.DispatchRecipe (queue worker 0x0) 0.1
    • batch 418: 41.6 ms at 8994 ms, present 3353: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 1.0, Driver.Packet.dispatch (queue worker 0x0) 0.9, Driver.Dispatch (queue worker 0x0) 0.9, Vulkan.DispatchRecipe (queue worker 0x0) 0.4
    • batch 716: 41.5 ms at 16275 ms, present 3358: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 2.3, Driver.Packet.dispatch (queue worker 0x0) 2.1, Driver.Dispatch (queue worker 0x0) 2.1, Vulkan.DispatchRecipe (queue worker 0x0) 0.8
    • batch 948: 41.5 ms at 21035 ms, present 3362: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.3, Driver.Packet.dispatch (queue worker 0x0) 0.2, Driver.Dispatch (queue worker 0x0) 0.2, Vulkan.DispatchRecipe (queue worker 0x0) 0.2
    - **A title where the cache pays:** Planet of Lana (PPSA19450), one profiled boot of a8e7e2f (the same build, relinked for that title), with its own usual switches: `APS5_STORAGE_CACHE_ENTRIES=1024 APS5_THREAD_PRIORITY=high APS5_PROFILE_DRAW=1` (`APS5_STORAGE_CACHE_ENTRIES` is fix(agc): cap the storage-image cache by entry count #14220's cap, which isn't on `main`), no LAZY or NO_GPL, and a cold shader cache. It ran 15 min through the logos into its menu. Not a timing run. - **No `bypassed` line in the whole run.** The hit rate per 10 s block stayed between 15.8% and 75.0%, median 19.8%: 1,262,160 hits in 6,381,888 lookups. - The cache sat at its 4,096-entry cap, ~14-15.5 MiB of the 256 MiB budget, turning over by entry count.
  • Resident Evil Village (PPSA01556), with the draw-cache budget off (an earlier pair, 2026-10-28 morning). Static main menu, 16 min each run after an unmeasured warm-up, unprofiled, B A A B.

    • Machine: Windows 11 (10.0.26300), RTX 3070 Laptop GPU (NVIDIA 617.42), Ryzen 9 5900HS, 16 GB. GPU clocks weren't held, so frame times are rough.
    • Binary: one binary for all four runs, a local tree with the same code as this PR: main 85a4d7f plus fix(agc): bound the draw cache by bytes #9129 and fix(agc): put a retired import's unchanged ranges back in the write watch #8926 (both merged since), our local table-index and Village-harness commits, a local scePadOpen answer and a diagnostic print, with the bypass commit on top (7bc49ce).
    • Environment: APS5_LAZY_SHADER_PREPARE=1 APS5_NO_GPL=1 APS5_HOST_IMPORT_MIB=6400 APS5_TRACE_SUMMARY_EVERY=10, and APS5_DRAW_CACHE_BYTES=1099511627776 (budget off) in every run.
    • Arms: A sets APS5_DRAW_CACHE_BYPASS_PERCENT=0 (no bypass); B leaves it unset (5%).
    B: bypass A: no bypass
    private bytes at menu +15 min 19,466 / 19,310 MB 23,187 / 23,186 MB
    private bytes at menu +1 min 16,732 / 16,623 MB 19,074 / 18,253 MB
    presents over menu +5 to +15 min (fps) 286 (0.477) / 279 (0.465) 246 (0.410) / 212 (0.353)
    frame p50 / p90 2.1 / 2.4 s and 2.1 / 2.3 s 2.4 / 2.9 s and 2.9 / 3.6 s
    Driver.Packet ms per frame 5,987 / 6,211 7,173 / 8,228
    Driver.Packet.memory_wait ms per frame 3,620 / 3,728 4,397 / 5,081
    • Memory: B is 3.8 GB lower at menu +15, and its two runs agree within 0.2 GB.
    • Speed: A slowed between its runs (0.410 to 0.353) while B held, so the gap is 0.06 to 0.12 fps.
    • All four runs are in the title's high host-import mode. B's second run made 172 GB of imports against 62 to 71 GB in the others, with private bytes and fps matching its first run.
    Summary lines (the last interval of B's and A's first runs)
    {"commit":"7bc49ce4d0c9","dirty":false,"env":{"APS5_DRAW_CACHE_BYTES":"1099511627776","APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SUMMARY_EVERY":"10"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"summary_every 10","first_present":2733,"ms":10862.659},"interval_start_s":1257.191,"interval_end_s":1268.054,"presents":6,"frame_ms":{"p50":1836.380,"p90":1928.612,"p99":1928.612,"max":1928.612},"gpu_busy_ms_per_present":266.715,"worker_busy_pct":{"queue worker 0x0":99.663,"queue worker 0x38":0.126,"queue worker 0x20":93.060,"queue worker 0x28":96.135},"top_phases_ms_per_frame":{"Driver.Packet":5229.249,"Driver.Packet.memory_wait":3160.711,"Driver.Packet.draw":1490.415,"Driver.Draw":1489.694,"Graphics.Draw":1355.575,"Graphics.Draw.draw_and_resource_release":1337.340,"Resources.Complete":598.582,"Driver.Packet.dispatch":515.536},"trace_dropped":false,"trace":""}
    {"commit":"7bc49ce4d0c9","dirty":false,"env":{"APS5_DRAW_CACHE_BYPASS_PERCENT":"0","APS5_DRAW_CACHE_BYTES":"1099511627776","APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SUMMARY_EVERY":"10"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"summary_every 10","first_present":2514,"ms":10370.633},"interval_start_s":1225.751,"interval_end_s":1236.122,"presents":5,"frame_ms":{"p50":2120.289,"p90":2197.734,"p99":2197.734,"max":2197.734},"gpu_busy_ms_per_present":269.083,"worker_busy_pct":{"queue worker 0x0":99.701,"queue worker 0x38":0.114,"queue worker 0x20":93.775,"queue worker 0x28":96.549},"top_phases_ms_per_frame":{"Driver.Packet":6013.220,"Driver.Packet.memory_wait":3677.704,"Driver.Packet.draw":1713.861,"Driver.Draw":1713.070,"Graphics.Draw":1491.831,"Graphics.Draw.draw_and_resource_release":1471.150,"Resources.Complete":683.281,"Driver.Packet.dispatch":522.495},"trace_dropped":false,"trace":""}
    

    The traces themselves, the four runs' aps5-summary.jsonl files with every 10 s interval, stay on the test machine. tools/trace_digest.py's text output for the same two runs is in a comment. Those lines share one commit because the arms differ only in the environment. The pair above compares main and this PR as two builds.

  • 58171b2, a merge of main edf6804 (run, validation run). The merge was clean: CMakeLists.txt, Driver.hpp and ENVIRONMENT.md merged without conflicts, and the PR's patch-id is unchanged. The Village pair, the captures and the profiled runs above were measured on a8e7e2f, whose patch this merge doesn't change.

    • The two bypass tests and every ^agc_driver_draw_cache test ×10. Linux: 13 run, 13 pass, 0 skip, 0 fail. Windows: 13 run, 0 pass, 13 skip, 0 fail, since the runner has no Vulkan device. The libc and libkernel suites run 191 and 291 tests on Linux and 220 and 314 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
    • Validation (VERIFY_VALIDATION=1 on GitHub's Linux runner, llvmpipe (LLVM 20.1.2, Mesa 25.2.8)), main edf6804 against 58171b2: 13 passed, 0 skipped. main has no bypass tests, so its arm ran the other ^agc_driver_draw_cache tests. VUID-VkDeviceCreateInfo-pNext-pNext appears in both arms, and the merge adds none.
  • 14209e9, a merge of main ebb4075, on top of c7981bc and 40973d3 (run, validation run). The merge was clean.

    • Every ^agc_driver_draw_cache test ×10, the bypass and cold-scene tests included:
      • Linux: 15 run, 15 pass, 0 skip, 0 fail.
      • Windows: 15 run, 0 pass, 15 skip, 0 fail, since the runner has no Vulkan device.
      • The libc and libkernel suites run 193 and 294 tests on Linux and 223 and 317 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
    • Validation (VERIFY_VALIDATION=1 on GitHub's Linux runner, llvmpipe (LLVM 20.1.2, Mesa 25.2.8)), main ebb4075 against this head:
      • 15 passed, 0 skipped. main has no bypass or cold-scene tests, so its arm ran the other ^agc_driver_draw_cache tests.
      • VUID-VkDeviceCreateInfo-pNext-pNext appears in both arms, and the change adds none.
  • 05d2faa: 11e29b3, the window race fix, then a merge of main 76fd1c0 (run, validation run). The merge was clean.

    • Every ^agc_driver_draw_cache test ×10, ConcurrentClosesKeepTheirOrder included:
      • Linux: 15 run, 15 pass, 0 skip, 0 fail.
      • Windows: 15 run, 0 pass, 15 skip, 0 fail, since the runner has no Vulkan device.
      • The libc and libkernel suites run 194 and 294 tests on Linux and 224 and 317 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
    • Validation (VERIFY_VALIDATION=1 on GitHub's Linux runner, llvmpipe (LLVM 20.1.2, Mesa 25.2.8)), main 76fd1c0 against this head:
      • 15 passed, 0 skipped.
      • VUID-VkDeviceCreateInfo-pNext-pNext appears in both arms, and the change adds none.
  • Resident Evil Village (PPSA01556) on the new base, draw cache at main's defaults, static main menu, B A A B, one block, 2026-10-29 (PT), unprofiled.

    B: 14209e9 A: main ebb4075
    fps over menu +5 to +15 min 0.523 / 0.495 0.527 / 0.651
    frame p50 / p90 1.82 / 2.19 s and 1.93 / 2.36 s 1.83 / 2.31 s and 1.43 / 1.79 s
    Driver.Packet ms per frame (median) 5,163 / 5,641 5,283 / 4,150
    Driver.Packet.memory_wait ms per frame (median) 3,051 / 3,270 3,133 / 2,450
    • No measurable gain in this pair.
      • B averages 0.509 fps and A 0.589.
      • A's own spread is 21.1 % (its second run is the high one), and B's is 5.5 %.
      • The b1/a1 same-phase pair is a tie (−0.8 %).
      • One block can't say more than that.
  • 1679477, the tests' cost (test-only):

    • Why: on an NVIDIA RTX 2000 Ada with the validation layers on, the four bypass tests ran past ctest's 120 s timeout and took 146 to 326 s alone. There, each draw that misses the cache or is bypassed costs about 10 to 20 ms.

    • What changed: the low-hit-rate and stage-hit cases draw only the lookups whose outcome they check, and note the rest of each 2,048-lookup window on the driver's bypass through DriverTestAccess. The cold-scene case keeps only its 1,000-draw scene, the one that is red on the head before the warm-up fix. No production code changed.

    • What moved: the draw-level checks stay draw-level, with fewer draws, including the draw whose pixel constant changed and must write the new colour. The third low window's 4,096-draw bypass, the draw after it, and the window of hits that ends a run are LowWindowsLengthenTheBypass's, which now also requires that no draw is bypassed before the window that starts the bypass has closed. The stage-hit case now notes one low window first, so stage hits that didn't count as useful would start a bypass.

    • Times on GitHub's Linux runner (llvmpipe), 05d2faa against this head:

      test ×10, without validation with validation
      agc_driver_draw_cache_cold_scene 8.83–11.50 s → 0.88–1.10 s 18.78 s → 2.87 s
      agc_driver_draw_cache_cold_scene_off 8.78–11.57 s → 0.85–1.12 s 19.13 s → 2.83 s
      agc_driver_draw_cache_low_hit_bypass 8.31–10.49 s → 0.44–0.65 s 17.45 s → 1.16 s
      agc_driver_draw_cache_low_hit_bypass_off 5.65–6.59 s → 0.50–0.67 s 10.47 s → 1.04 s
    • ×10 (run), every ^agc_driver_draw_cache test:

      • Linux: 15 run, 15 pass, 0 skip, 0 fail.
      • Windows: 15 run, 0 pass, 15 skip (no Vulkan device), 0 fail.
      • The libc and libkernel suites run 194 and 294 tests on Linux and 224 and 317 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
    • Validation (run), main 76fd1c0 against this head: 15 passed. VUID-VkDeviceCreateInfo-pNext-pNext appears in both arms, and the change adds none.

    • Still red on 58171b2, the head before the warm-up fix (run): the trimmed agc_driver_draw_cache_cold_scene fails with "frame 4 of a scene that repeats the same 1000 new draws every frame hit 0 of them, expected at least 90%", and its _off arm passes. On Windows both skip.

  • Resident Evil Village (PPSA01556) on 1679477, main 6472c70, draw cache at main's defaults, static main menu. B A A B, one block, 2026-10-30 (PT), unprofiled.

    run fps over menu +5 to +15 min frame p50 / p90 private bytes at menu +15
    b1 (B) 0.666 1.43 / 1.86 s 14,123 MB
    a1 (A) 0.588 1.65 / 2.08 s 14,139 MB
    a2 (A) 0.583 1.70 / 2.06 s 13,941 MB
    b2 (B) 0.660 1.47 / 1.76 s 14,085 MB
    • As measured: B's mean is 0.663 fps against A's 0.585 (+13.3%), and both B runs are above both A runs. The two A runs are within 0.9% of each other, and the two B runs within 1.0%. Median phases, B against A: Driver.Packet 4,176 against 4,828 ms per frame, Driver.Packet.draw 1,120 against 1,294, and memory_wait 13.8% lower.

    • Load: non-game CPU in the window was 43.8, 42.9, 41.8 and 36.1%. b2 ran lighter than the other three. On the three within 2 points of each other, b1 against the A mean is +13.9%.

    • Health: no failed host imports and no stop line, and the menu was first seen at +5.5 to +6.2 min. a1, a2 and b2 each logged one presenter FATAL at close time, after the window. Pixel comparison of the static regions at menu +10 shows B rendering like A.

    • Not attributed to this change. One profiled boot of each tree, with APS5_PROFILE_DRAW=1 added, over the same window. That switch turns off the finisher hand-off, so the boots are compared only with each other:

      • The bypass: B printed [draw-cache] bypassed in 0 of the window's 57 ten-second blocks. All 12 of its bypass lines came during loading, 50 to 610 s after launch.
      • The cache, in both: 0 hits in every block. It sat at 255 of its 256 MiB, and every eviction was over the byte budget. Lookups per 10 s were about the number of draw packets (medians: A 4,288, B 5,208).
      • The code: with the bypass off, this head does no less work per draw than main. It adds a drawKeySeen lookup under drawCacheMutex for each lookup that doesn't hit, a relaxed atomic load per draw and a compare-exchange per lookup.
      • The profiled boots' times aren't compared: A's boot ran with 48.7% non-game CPU against B's 37.4%.
      • So the pair's gain isn't explained by the bypass, and this description claims no speed gain.
    • Captures, as the Performance report form describes: one traced run per arm on the same trees and cache, A (16:21–16:43) then B (16:44–17:06) in one session, with APS5_TRACE_SECONDS=960:30 and the pad replay, and no other trace or profile switch. The window opens 960 s after the first present, at about menu +11 min. Neither trace dropped events. GPU clocks weren't logged for these two runs.

      • B against A over the window: 22 presents each; frame p50 1,358 against 1,401 ms, p90 1,505 against 1,709 ms, p99 1,681 against 1,986 ms; Driver.Packet 3,884 against 4,051 ms per frame, of which memory_wait 2,284 against 2,363 and Packet.draw 1,054 against 1,065; GPU busy per present 237 against 248 ms.
      • The traces: A aps5-trace-237e88d4ff9c-28876.json.gz (2.6 MB) and B aps5-trace-05bae016f8dd-11428.json.gz (2.4 MB). Their tools/trace_digest.py output is in this comment.
      • Both summary lines say "dirty": true. That's trace_revision.cmake's porcelain check seeing only 3rdparty/freetype as modified: main's new freetype pin has a nested subprojects/dlg that can't be fetched. With submodule content ignored, the status is empty, the same in both trees, so neither tree has a source change beyond its commit.
      • The summary lines, as aps5-summary.jsonl holds them (A, then B):
      {"commit":"237e88d4ff9c","dirty":true,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":2821,"ms":31663.912},"presents":22,"frame_ms":{"p50":1400.899,"p90":1708.722,"p99":1985.646,"max":1985.646},"gpu_busy_ms_per_present":248.362,"worker_busy_pct":{"queue worker 0x0":99.512,"queue worker 0x38":0.083,"queue worker 0x28":93.381,"queue worker 0x20":88.858},"top_phases_ms_per_frame":{"Driver.Packet":4051.385,"Driver.Packet.memory_wait":2363.248,"Driver.Packet.draw":1064.743,"Driver.Draw":1063.573,"Graphics.Draw":834.753,"Graphics.Draw.draw_and_resource_release":812.4,"Driver.Packet.dispatch":565.972,"Driver.Dispatch":515.708},"trace_dropped":false,"trace":"aps5-trace-237e88d4ff9c-28876.json.gz"}
      {"commit":"05bae016f8dd","dirty":true,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":2834,"ms":30167.48},"presents":22,"frame_ms":{"p50":1358.259,"p90":1505.007,"p99":1680.983,"max":1680.983},"gpu_busy_ms_per_present":237.445,"worker_busy_pct":{"queue worker 0x0":99.552,"queue worker 0x38":0.053,"queue worker 0x20":89.735,"queue worker 0x28":94.132},"top_phases_ms_per_frame":{"Driver.Packet":3883.824,"Driver.Packet.memory_wait":2284.046,"Driver.Packet.draw":1054.258,"Driver.Draw":1053.291,"Graphics.Draw":846.766,"Graphics.Draw.draw_and_resource_release":828.217,"Driver.Packet.dispatch":505.62,"Driver.Dispatch":445.217},"trace_dropped":false,"trace":"aps5-trace-05bae016f8dd-11428.json.gz"}
  • eaafdf9, the cold-scene case's cost (test-only; DrawCacheReuse.cpp, +6 −3). The pair above ran on 1679477's library code, which this head doesn't change.

    • Why: on TechLevelZero's NVIDIA run of 1679477, agc_driver_draw_cache_cold_scene and _off took 93.3 and 94.8 s with the validation layers on. Each arm drew a 1,000-draw scene for 4 frames, 4,000 draws.
      • Under the two-low-windows rule, that scene had also stopped depending on the warm-up: its first window held 48 hits and its second was useful, so it stayed green with the warm-up taken out.
    • What changed: the case notes one low window on the driver's bypass, as the stage-hit case does. It then draws a 128-draw scene for 4 frames and closes the window after the second frame: 512 draws per arm.
      • With the warm-up, the window's 128 second sightings are useful (more than the 103 of 5% of 2,048), so the run of low windows ends and frame 4 hits.
      • Without it, that window is the second low one in a row, and frame 4 is bypassed.
      • The assertion (at least 90% hits in frame 4), the frame count and the _off arm are unchanged.
    • Red (Linux, lavapipe), each mutation built and reverted:
      • the warm-up off (|| drawKeySeen(drawKey) removed from drawCacheBypass.Note(...)): the default arm fails, "frame 4 of a scene that repeats the same 128 new draws every frame, after a low window and with the scene's first two frames closing the next one, hit 0 of them, expected at least 90%";
      • that plus APS5_DRAW_CACHE_BYPASS_PERCENT ignored: the _off arm fails too;
      • the bypass after one low window (LowWindowsToBypass = 1): the default arm fails.
      • 1679477's 1,000-draw case passes all three.
    • Times on lavapipe, three runs each: plain, 0.89 s before and 0.21 s after; with the validation layer, 2.3 s before and 0.47 s after. On NVIDIA, TechLevelZero's run on this head (report) took 15.3 and 14.8 s for the two arms with the validation layers on, against 93.3 and 94.8 s on 1679477. It passed with 0 new failures and no new validation IDs.
    • ×10 (run), every ^agc_driver_draw_cache_ test:
      • Linux: 15 run, 15 pass, 0 skip, 0 fail.
      • Windows: 15 run, 0 pass, 15 skip (no Vulkan device), 0 fail.
      • The libc and libkernel suites run 194 and 294 tests on Linux and 224 and 317 on Windows, with 0 failed. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • da441e0, a merge of main 0836dfd (run). build(agc): register each AGC test executable in its own CMake fragment #12862 moved libSceAgcDriver's test registrations into tests/cmake/; the conflict in CMakeLists.txt is resolved with tools/agc_test_split.py resolve, which moves this PR's registrations into tests/cmake/agc_driver_draw_cache_reuse_tests.cmake (+12 lines). Nothing else conflicted. Apart from the move, this PR's diff is unchanged. With -DBUILD_TESTING=ON, ctest -N gives 3079 tests: main's 3075 plus its 4 tests, each listed once. The 16 tests matching ^agc_driver_draw_cache_ pass 10 runs in a row. Linux: 16 run, 16 pass, 0 skip, 0 fail. Windows: 16 run, 0 pass, 16 skip (no Vulkan device), 0 fail. Suites: libc and libkernel pass on Linux (199 and 308) and on Windows (226 and 330). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.

  • NVIDIA, TechLevelZero's GPU runner (report): da441e0 merged onto main 0836dfd, NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Linux. Passed: 2,447 passed, 0 new failures (4 fail on main too, and 2 are unstable there), and no new validation IDs against main over 928 tests run on the GPU.

Checklist

  • Based on current main; no other open PR implements the same functions (see Overlap)
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file: n/a, none added
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source: n/a, none
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 3070 Laptop GPU, driver 617.42, Windows 11 (10.0.26300); llvmpipe (lavapipe) on GitHub's Linux runner
  • AI-assisted: yes

After a window of 2048 draw-cache lookups with fewer than 5% hits, the
next 16384 draws neither look up nor insert draw entries; lookups then
resume and a new window is measured. APS5_DRAW_CACHE_BYPASS_PERCENT
sets the threshold, and 0 never bypasses.

Co-authored-by: Benjamin Cortez <benjacortezf@gmail.com>
@github-actions github-actions Bot added perf Performance change perf numbers missing perf pull request without a before and after summary line labels Oct 28, 2026
@github-actions

Copy link
Copy Markdown

This pull request is labeled perf, so it needs the summary line of a capture on main and one with the change, from the same title, scene and machine, as the Performance report form asks. Please paste both aps5-summary.jsonl lines, attach the two traces and add the output of tools/trace_digest.py.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the exact head 3e4d8e25f2. Two items need resolution before approval.

  1. APS5_DRAW_CACHE_BYPASS_PERCENT=5 is documented as bypassing when fewer than 5% of 2,048 lookups hit. But minimumHits = 2048 * 5 / 100 truncates to 102, and the test explicitly treats 102/2,048 (4.9805%) as meeting the threshold. If the documented percentage is literal, the minimum count should be ceil(2048 * percent / 100) (103 for 5%), and the boundary test should cover 102 versus 103. Alternatively, document that the integer threshold is rounded down and test that contract.

  2. The perf evidence still does not show the required main-versus-change capture. The summary lines in the body use commit 7bc49ce4d0c9 for both bypass-on and bypass-off runs; setting APS5_DRAW_CACHE_BYPASS_PERCENT=0 on the changed binary is a useful control, but it is not a capture on main. The red/green test run is on main 04fefebe90, and the requested VERIFY_VALIDATION=1 comparison is still listed as running. Please add matched main and exact-head captures/traces/digests and finish the validation comparison on the current base f8f5b24b77ad. I did not independently run the GPU tests or capture.

…each window once

A lookup now counts as a hit for the bypass window when the whole draw
hit, or when a draw whose key missed found a cached stage of its shape
to reuse, so a scene that only reuses stages is not bypassed. The
window's lookups and hits share one 64-bit atomic updated by a single
compare-exchange, so concurrent queue workers close each window exactly
once.
…tage

The window's minimum hit count rounds Window * percent / 100 up instead
of down, so a window bypasses the cache exactly when fewer than the
configured percent of its lookups hit: at 5%, 102 hits in 2048 (4.98%)
now start the bypass and 103 (5.03%) keep the cache. 0 still never
bypasses and 100 still needs all 2048.
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 14794 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp L390

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 1896 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
docs/dev/ENVIRONMENT.md
PR 4472 docs/dev/ENVIRONMENT.md
PR 5609 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawCache.hpp
core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCache.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
PR 6186 docs/dev/ENVIRONMENT.md
PR 6188 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawCache.hpp
core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCache.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCacheStatistics.cpp
core/libs/prx/libSceAgcDriver/tests/execution/DrawCacheReuse.cpp
PR 6804 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
PR 6924 docs/dev/ENVIRONMENT.md
PR 7275 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
PR 7449 docs/dev/ENVIRONMENT.md
PR 7457 docs/dev/ENVIRONMENT.md
PR 7514 docs/dev/ENVIRONMENT.md
PR 7604 docs/dev/ENVIRONMENT.md
PR 8004 docs/dev/ENVIRONMENT.md
PR 8246 docs/dev/ENVIRONMENT.md
PR 8484 docs/dev/ENVIRONMENT.md
PR 9012 docs/dev/ENVIRONMENT.md
PR 9289 docs/dev/ENVIRONMENT.md
PR 9335 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawCache.hpp
core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
PR 9345 docs/dev/ENVIRONMENT.md
PR 9356 docs/dev/ENVIRONMENT.md
PR 9387 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
docs/dev/ENVIRONMENT.md
PR 9676 docs/dev/ENVIRONMENT.md
PR 9852 docs/dev/ENVIRONMENT.md
PR 10193 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawCache.hpp
core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_draw_cache_reuse_tests.cmake
docs/dev/ENVIRONMENT.md
PR 10359 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
PR 10442 docs/dev/ENVIRONMENT.md
PR 10678 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
docs/dev/ENVIRONMENT.md
PR 10757 docs/dev/ENVIRONMENT.md
PR 10894 docs/dev/ENVIRONMENT.md
PR 11436 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
docs/dev/ENVIRONMENT.md
PR 12324 docs/dev/ENVIRONMENT.md
PR 12565 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
PR 12849 docs/dev/ENVIRONMENT.md
PR 13486 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
docs/dev/ENVIRONMENT.md
PR 13793 docs/dev/ENVIRONMENT.md
PR 13809 docs/dev/ENVIRONMENT.md
PR 13863 docs/dev/ENVIRONMENT.md
PR 13920 docs/dev/ENVIRONMENT.md
PR 13928 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawCache.hpp
core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_draw_cache_reuse_tests.cmake
docs/dev/ENVIRONMENT.md
PR 13929 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawCache.hpp
core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_draw_cache_reuse_tests.cmake
docs/dev/ENVIRONMENT.md
PR 14051 docs/dev/ENVIRONMENT.md
PR 14943 docs/dev/ENVIRONMENT.md
PR 15059 docs/dev/ENVIRONMENT.md
PR 15169 docs/dev/ENVIRONMENT.md
PR 15529 docs/dev/ENVIRONMENT.md
PR 15548 docs/dev/ENVIRONMENT.md
PR 15570 docs/dev/ENVIRONMENT.md

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@MarcZX10 thanks for the review. Where each point stands at a8e7e2f:

  1. The threshold is now exact. b7001db makes the minimum ceil(2048 × percent / 100), 103 hits at 5%. So 102 hits in 2,048 lookups (4.98%) bypasses and 103 keeps the cache, as "fewer than 5%" says. LowHitRateBypassesTheCache now covers 102 against 103. It fails on the parent commit ("draws after a window of 102 hits in 2048 lookups were still looked up or inserted") and passes with the change.
  2. Evidence.

Also new since your review: ab71996 counts a draw as a window hit when one of its stages is reused from a cached draw of the same shape. It also keeps the window in one compare-exchange, so exactly one caller closes each window. Its tests are StageHitsKeepTheCacheLookedUp and ConcurrentNotesCloseEachWindowOnce.

@github-actions github-actions Bot removed the perf numbers missing perf pull request without a before and after summary line label Oct 29, 2026
@EagleBearerYS
EagleBearerYS marked this pull request as ready for review October 29, 2026 03:33
@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@MarcZX10 the matched captures are in the description's Tested section now: Resident Evil Village (PPSA01556)'s static main menu with the draw cache at main's defaults, main 319621b against this head a8e7e2f, B A A B, unprofiled, with the summary lines, one trace per arm and their trace_digest.py output. This head's mean is 0.866 fps against main's 0.688 (+26%), and it's ahead in both adjacent pairs, with no difference in memory. GPU clocks weren't held. The threshold and the validation run are covered in my reply above, so could you take another look?

@adriadam10 adriadam10 self-assigned this Oct 29, 2026

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-checked — changes requested

The new report fixes the threshold/stage-hit findings and includes paired traces and digest output, but it still does not meet the performance form’s capture requirements, and this head is based on an older main that changed two touched paths.

What I ran

  • Reviewed exact head a8e7e2f8a72888acfc3aa9bcb4c9a90bb711f0b8 against current main 52c09d567d2fa453494dd720fcf53a98149468e4.
  • Ran git merge-tree --write-tree, git diff --check, and compared paths changed on current main since the PR merge base.
  • Inspected the updated threshold/concurrency implementation and tests, validation results, performance comparison, trace links, digest output, and the current performance report form.

Results

Check Result
Current-main preview Clean; tree c2666560a7cb061410bce876ecbe3881bbca4589
Branch base Merge base 319621ba2e578bd053b0baba2877fe70520e0737; current main has 204 later commits
Same paths changed on current main core/libs/prx/libSceAgcDriver/CMakeLists.txt and core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
Focused tests Author reports 13/13 Linux tests on exact PR head and red/green tests for the earlier commits; Windows GPU tests ran only on the first commit, while the GitHub Windows runner has no Vulkan device
Validation comparison Author reports 13/13 tests with no new VUIDs on llvmpipe for head a8e7e2f8a7 vs main 319621ba2e
Performance comparison Author provides main/head runs on the same Resident Evil Village menu, Windows 11, RTX 3070 Laptop GPU, driver 617.42, Ryzen 9 5900HS, and trace digests; reports +26% mean FPS and lower frame p90
Report-form gaps No raw aps5-summary.jsonl lines are pasted for the paired main/head captures. The captures set APS5_TRACE_SUMMARY_EVERY=10, an additional APS5_TRACE_* switch prohibited by the form
Raw output
$ git merge-tree --write-tree refs/review/main-20261029b refs/review/pr-12478-20261029
c2666560a7cb061410bce876ecbe3881bbca4589
exit=0
merge-base: 319621ba2e578bd053b0baba2877fe70520e0737
current main: 52c09d567d2fa453494dd720fcf53a98149468e4
main commits after base: 204
changed-path intersection:
core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
$ git diff --check refs/review/main-20261029b...refs/review/pr-12478-20261029
(no output)

Negative control

  • The author reports the new boundary test fails with 102/2,048 hits on the previous floor-threshold commit and passes with the corrected ceiling threshold; the stage-hit and concurrent-window tests also distinguish the earlier implementation. I did not rerun these locally.

Findings

Blocking

  • The performance report describes the two JSON blocks as trace_digest.py output and says the aps5-summary.jsonl files stay on the test machine. The report form requires the actual summary line for each compared capture. Please paste the exact aps5-summary.jsonl line from the main run and the exact line from this-head run; the digest JSON objects are not substitutes for those lines.
  • The paired captures include APS5_TRACE_SUMMARY_EVERY=10, in addition to the permitted APS5_TRACE_SECONDS=960:40. The form explicitly says to set no other APS5_TRACE_* or APS5_PROFILE_* switch because they cost time. Please recapture the same main/head scene without that extra switch, paste both summary lines, attach the two traces, and include trace_digest.py output for those exact traces.
  • Rebase onto current main and rerun the focused draw-cache tests and validation comparison on that exact integrated head. Current main changed both CMakeLists.txt and Driver.hpp after this branch’s base, so the existing exact-head test and performance reports do not cover the current tree.

Non-blocking

  • The updated implementation now uses a 64-bit compare-exchange window, counts stage hits, and rounds the minimum hit count up; the focused cases cover the 102/103 boundary, cache resume, stage reuse and concurrent closure. Those changes address the earlier code findings.
  • The reported main-menu capture shows no material memory reduction at the default 256 MiB budget; it reports a speed improvement, but Packet.dispatch is higher on the change. Keep both effects visible in the report.

Sources

Not verified

  • I did not rerun the tests, validation comparison, captures, or digest locally. The tests and performance evidence are author-reported. The current-main preview is clean but does not substitute for a current-base test run.

To get this to a good state

Rebase onto current main, rerun the focused draw-cache/validation tests, then capture main and the rebased head on the same machine and scene with only the required trace setting. Paste the exact two aps5-summary.jsonl lines, attach those two traces, and include digest output generated from those same traces.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@MarcZX10 the captures are redone as the Performance report form describes and are in the description's Tested section: one traced run per arm with APS5_TRACE_SECONDS=960:30 as the only trace switch, both aps5-summary.jsonl lines pasted as the files hold them, the two traces, and trace_digest.py on each. This head leads again: 24 presents against main's 19 in the window, and frame p50 1,264 against 1,510 ms. Packet.dispatch is lower in this head this time, 526 against 565 ms, and GPU busy per present is higher, 244 against 232 ms; both are listed. GPU clocks weren't held. Could you take another look?

@MarcZX10

Copy link
Copy Markdown
Contributor

Re-check — changes still requested

Thanks for replacing the earlier captures. The updated report now includes two raw aps5-summary.jsonl lines, both traces, digest output, the same scene/machine, and only APS5_TRACE_SECONDS=960:30 as a trace switch. The latest pair reports 24 presents versus 19 and lower frame p50 on the change, while also showing the clock difference and the higher GPU-busy-per-present result.

What I checked

  • Reviewed exact PR head a8e7e2f8a72888acfc3aa9bcb4c9a90bb711f0b8 against current main edf6804cf52c62eacafc592dd6142cb4efe5bd05.
  • git merge-tree --write-tree upstream/main refs/review/upstream-12478: clean tree 784dba3ba56d7df96c77eff02f18f508950151c4.
  • git diff --check upstream/main...refs/review/upstream-12478: pass.
  • python3 tools/check_conventions.py --base upstream/main: pass.
  • Current main has changed two PR-touched paths since the branch base: CMakeLists.txt and Driver.hpp. The latter now supplies ThreadDimensionGroups, used in dispatch and buffer copy/fill paths. The new report's summary commit IDs (103015a9ca66 and bd421aa3c2fb) do not resolve in the upstream or PR-fork commit API, so I cannot verify which exact published trees were captured as main and change.

Results

Check Result
Updated performance report form Summary lines, traces and digest output are now present; prohibited extra trace switches were removed
Current-main merge preview Clean
Diff check and conventions Pass
Current-base tests and validation Not yet reported on current main
Capture source provenance The abbreviated commit IDs are not reachable from the public upstream or PR fork

Negative control

The report includes main/change captures and test-level red/green controls, but the source commits for the summary lines are not currently resolvable from either public repository. I cannot independently verify the baseline/change provenance from those IDs.

Findings

Blocking

  • Please rebase onto current main, rerun the focused draw-cache tests and Vulkan validation comparison on that integrated head, and refresh the paired performance capture if the resulting code changes. The current main update changed a test-registration file and Driver.hpp, which is used by dispatch/buffer paths.
  • Please provide full, reachable commit IDs or public refs for the two captured trees and identify which is current main and which contains this PR. The current 12-character commit values cannot be found in either repository, so I cannot verify the required main-versus-change comparison yet.

Non-blocking

The updated report correctly surfaces GPU clock variation and the higher GPU-busy-per-present number rather than presenting the frame-time gain alone. No new source-code finding was identified in this re-check.

Sources

Not verified

I did not rerun the GPU tests, validation comparison or captures. Those results are author-reported. The current-main merge, diff and conventions checks were run locally.

@MarcZX10

Copy link
Copy Markdown
Contributor

Rechecked your response and the updated performance report at head a8e7e2f8a72888acfc3aa9bcb4c9a90bb711f0b8.

Addressed: The replacement captures now follow the performance form: one APS5_TRACE_SECONDS=960:30 run per arm, no other trace/profile switches, both summary lines, both traces, and digest output. The report also presents the GPU clock difference and the per-present GPU busy and Packet.dispatch changes instead of hiding them. This resolves my earlier capture-format findings.

Still needed: The compared main tree is 319621ba2e, while current main is 4c7d275bef89. Current main has since changed CMakeLists.txt and Driver.hpp, both files touched by this PR. The merge preview is clean, but the focused draw-cache tests and validation comparison do not cover that integrated tree. Please rebase onto current main and rerun the focused tests and validation comparison on that head. The captures can remain labeled with the exact older trees they measured; they should not be represented as measurements of the rebased code unless recaptured.

I did not run a local AGC build or GPU capture in this workspace. The current workspace has no Vulkan device.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@MarcZX10 this head, 58171b2, merges main edf6804 cleanly with the PR's patch unchanged. The draw-cache tests pass ×10 on it, and the validation comparison against main adds no VUIDs. Both runs are in the description's last Tested bullet, and the capture trees are now linked under Trees. Could you take another look?

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed exact head 58171b22e89daedc60672482d0eb349b36609ac1 and your new test report. The draw-cache tests on this head and the validation-layer comparison are useful; they address the focused correctness run. The branch’s merge base is still edf6804cf52c62eacafc592dd6142cb4efe5bd05, not current main 4c7d275bef89d309313d16bc2bc05d37a1b50be2. Current main changed CMakeLists.txt and Driver.hpp, both touched by this PR. The report’s perf pair also remains against an older baseline, so please integrate current main, rerun the focused validation comparison, and refresh the matched performance capture against that current main and the resulting head. Merge preview is clean; diff check and conventions pass. I did not run GPU tests locally.

@bcortezf

Copy link
Copy Markdown
Contributor

Tested on NVIDIA RTX 4070 SUPER (driver 616.64), Windows 11 Pro 26200, MinGW-w64 GCC, Release, BUILD_TESTING=ON.
Base: main 899ae3d + head 58171b2 (clean merge).

  • Positive: the 13 agc_driver_draw_cache* tests pass 3/3 (ctest --repeat until-fail:3), including low_hit_bypass and low_hit_bypass_off.

  • Negative control: with main's Draw.cpp, agc_driver_draw_cache_low_hit_bypass fails with draws after a window of 102 hits in 2048 lookups were still looked up or inserted; _off passes.

  • Warm-up regression (blocking for me): a scene that repeats the same F distinct draws every frame, starting cold. Local experiment on top of the PR's test (--warmup F N, patch attached): N frames of ScaledDraws with F distinct scales, hits counted per frame. APS5_DRAW_CACHE_BYPASS_PERCENT=0 behaves like main.

    draws/frame bypass 0 (= main): first frame ≥90% hits bypass 5% (default): first frame ≥90% hits hits, frames 1..29, 5% vs 0
    700 2 2 19,601 vs 19,601
    1,000 2 19 11,617 vs 28,001
    2,000 2 19 23,233 vs 56,001
    3,000 2 14 (frames 1..11: 0 vs 30,001)
    4,096 2 18 (frames 1..11: 1 vs 40,961)

    Cause, as far as I can tell: with second-sight admission a draw only hits on its third sighting, so the first 2,048-lookup window after any scene change (or at boot) has almost no hits whenever a frame has more than ~700 distinct draws. The bypass then fires, and while it is active no sightings or inserts happen, so warming up takes several bypass cycles. At 60 fps that is ~0.3 s, at the 5–7 fps of heavy titles it is a few seconds of cold cache after every transition, and it is the cache's best case (fully repeated frames) that pays.
    Suggestion: count a lookup whose key DrawKeySightings has already seen (an admitted insert) as a hit for the window, or arm the bypass only after two consecutive low windows. Scenes whose keys never repeat (per-frame pointers in user data) would still bypass.

  • Minor: the window counts a draw as a hit when any dataCandidates[i] is non-empty, i.e. a cached draw of the same shape exists, before verifyDataStage/push-offset matching decides it is reused (Draw.cpp, the Note line after lookupDraw). It errs toward keeping the cache, so not harmful, but the description says "at least one of its stages is reused".

  • Minor: every bypassed draw takes drawCacheMutex only to bump drawEntryCounters.bypassed; an atomic (or counting only under APS5_PROFILE_DRAW) would avoid the lock on the path meant to be cheap.

  • Game: Red Dead Redemption (PPSA30528) on this main aborts in the menu (~20 s) with NGS2: this buffered voice parameter is not implemented (from c620e8e, not this PR), so no gameplay A/B. Before the abort, the menu's two 10 s profile windows show 96–99% hits and no bypassed line.

Not tested: AMD/Intel, Linux, validation layer, gameplay performance (blocked by the NGS2 abort above).

AI-assisted: yes (Claude Code)

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

Thanks for the RTX 4070 SUPER run and the warm-up table, @bcortezf. The warm-up case is a real regression, and the code agrees with your reading of the cause:

  • DrawCacheBypass::Note counts a lookup as a hit only when a cached draw of the same shape was found. With second-sight admission, the first two sightings of each draw are misses. On a cold start with enough distinct draws per frame, the first 2,048-lookup window ends before the third sightings, stays under 5 % and starts the bypass.
  • While the bypass runs, the draw skips the lookup and the insert, so no sightings are recorded either. Each bypass cycle moves admission on by very little, which matches your 14 to 19 frames against main's 2.

We'll add your scene as a test (a cold start, then the same F distinct draws every frame) and change the window so that the first sightings of a repeating scene don't start the bypass. Then we'll rerun the draw-cache tests and the performance pair.

Your two minor points go in with it:

  • The description will say what the window counts: a cached draw of the same shape, before the data and push-offset checks decide whether it's reused.
  • The bypass counter will become an atomic, so a bypassed draw no longer takes drawCacheMutex.

Thanks also for the Red Dead Redemption (PPSA30528) menu numbers (96 to 99 % hits, no bypassed line) before the NGS2 stop.

@MarcZX10

Copy link
Copy Markdown
Contributor

Re-checked — validation failure needs attribution

The exact-head NVIDIA report shows VUID-vkCmdCopyBuffer-commonparent in agc_driver_depth_clear_hle, but its main-plus-PR-test-only control did not build, so the report does not establish whether this is caused by the PR or by the test/harness path.

The attached reruns are inconsistent: one isolated run passed, and a later run segfaulted. Please provide a repeatable same-head result and isolate the test against main or explain why a comparable baseline cannot be built; if the ownership error is change-specific, please fix it. The existing review findings remain open.

Exact-head GPU logs and reruns.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the test commit: drawing only the lookups the cases check and noting the rest of each window on the bypass should cut the draw counts well below the 120 s timeout (the NVIDIA rerun on 1679477 will show it). One point still blocks this:

  • No benefit shown. The description still says the current head has no measurable gain, and the profiled Resident Evil Village boot is still "Pending". The PR is titled perf and adds a window, an env var and counters. Please post one scene where the bypass starts under the "seen before counts as useful" rule and the gain is outside noise, with tools/trace_digest.py summaries of main and the change from the same machine and scene. If no scene fires and helps, the direction is to drop the change.

Also, @MarcZX10 asked for the VUID-vkCmdCopyBuffer-commonparent in agc_driver_depth_clear_hle on the NVIDIA report to be attributed (same-head repeat, or the test against main); please answer that too.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

The tools/trace_digest.py text output for B's and A's first runs of the earlier Resident Evil Village (PPSA01556) pair with the draw-cache budget off (2026-10-28 morning), moved here from the description to keep it under GitHub's size limit. The pair's table and summary lines stay in the description.

tools/trace_digest.py, B's first run (bypass)

116 intervals, 0.0 to 1268.1 s, 2739 presents
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 3840x2160, commit 7bc49ce

# seconds presents p50 p90 p99 max GPU busy busiest worker largest phase
1 0-10 595 16.7 16.9 17.3 61.5 0.6 87 % Shader.ResolveGraphicsStagesAbi 63.0
2 10-20 600 16.7 16.9 17.0 17.1 0.6 90 % Shader.ResolveGraphicsStagesAbi 63.9
3 20-30 268 16.7 16.9 17.2 5466.1 1.2 88 % Shader.ResolveGraphicsStagesAbi 58.9
4 30-40 90 108.6 126.4 226.3 226.3 51.7 96 % Shader.ResolveGraphicsStagesAbi 481.1
5 40-50 81 108.5 132.7 608.8 608.8 53.6 96 % Shader.ResolveGraphicsStagesAbi 540.7
6 50-60 49 189.0 303.2 620.2 620.2 70.0 93 % Driver.Packet 559.9
7 60-70 60 163.6 184.6 196.0 196.0 69.2 96 % Driver.Packet 469.9
8 70-81 64 155.5 170.1 181.9 181.9 69.4 96 % Driver.Packet 440.6
9 81-91 61 164.4 179.1 192.8 192.8 70.2 96 % Driver.Packet 463.2
10 91-101 61 162.3 182.1 195.6 195.6 70.7 96 % Driver.Packet 462.1
11 101-111 61 161.9 180.6 191.8 191.8 70.6 96 % Driver.Packet 464.2
12 111-121 59 165.1 187.1 389.4 389.4 71.2 96 % Driver.Packet 466.4
13 121-131 62 151.9 167.7 405.0 405.0 67.8 95 % Driver.Packet 332.3
14 131-141 32 295.8 562.4 1222.1 1222.1 88.0 98 % Shader.ResolveGraphicsStagesAbi 874.6
15 141-151 31 330.7 355.9 376.1 376.1 135.8 98 % Shader.ResolveGraphicsStagesAbi 1647.9
16 151-161 24 340.4 362.8 2226.2 2226.2 142.7 98 % Driver.Packet 1070.1
17 161-172 2 8182.9 8182.9 8182.9 8182.9 800.4 100 % Driver.Packet 16088.1
18 172-182 5 2088.9 2261.2 2261.2 2261.2 294.4 100 % Driver.Packet 6006.4
19 182-194 6 1931.0 2265.0 2265.0 2265.0 272.7 100 % Driver.Packet 5602.5
20 194-206 6 1929.6 2148.8 2148.8 2148.8 274.8 100 % Driver.Packet 5686.8
21 206-217 5 2139.1 2375.1 2375.1 2375.1 217.0 100 % Driver.Packet 6260.1
22 217-227 4 2770.7 3106.4 3106.4 3106.4 342.1 100 % Driver.Packet 7391.7
23 227-237 5 1980.3 2331.1 2331.1 2331.1 278.1 100 % Driver.Packet 5908.4
24 237-247 5 2011.8 2540.7 2540.7 2540.7 271.1 100 % Driver.Packet 5963.6
25 247-258 5 2165.6 2243.5 2243.5 2243.5 220.6 100 % Driver.Packet 5911.3
26 258-269 6 1919.4 2023.3 2023.3 2023.3 318.0 100 % Driver.Packet 5473.3
27 269-279 5 2001.3 2447.0 2447.0 2447.0 217.0 100 % Driver.Packet 5835.4
28 279-291 6 2025.4 2115.1 2115.1 2115.1 315.6 100 % Driver.Packet 5596.0
29 291-302 6 1964.5 2100.3 2100.3 2100.3 225.2 100 % Driver.Packet 5643.3
30 302-314 6 1954.0 2100.9 2100.9 2100.9 270.9 100 % Driver.Packet 5694.7
31 314-326 6 1825.6 2219.7 2219.7 2219.7 319.5 100 % Driver.Packet 5441.3
32 326-336 5 1844.5 2575.7 2575.7 2575.7 215.8 100 % Driver.Packet 5801.7
33 336-347 6 1791.1 2319.8 2319.8 2319.8 272.9 100 % Driver.Packet 5613.2
34 347-358 6 1840.6 2017.2 2017.2 2017.2 269.5 100 % Driver.Packet 5338.6
35 358-370 6 1958.8 2081.5 2081.5 2081.5 315.1 100 % Driver.Packet 5672.3
36 370-381 6 1872.9 2072.0 2072.0 2072.0 225.4 100 % Driver.Packet 5458.6
37 381-393 6 1925.4 1972.5 1972.5 1972.5 312.8 100 % Driver.Packet 5407.6
38 393-404 6 1860.8 2184.9 2184.9 2184.9 270.7 100 % Driver.Packet 5517.2
39 404-415 6 1880.0 1929.0 1929.0 1929.0 225.2 100 % Driver.Packet 5391.1
40 415-427 6 1926.5 2118.8 2118.8 2118.8 271.0 100 % Driver.Packet 5618.0
41 427-438 6 1895.0 1944.3 1944.3 1944.3 316.4 100 % Driver.Packet 5403.3
42 438-450 6 1935.8 2105.0 2105.0 2105.0 270.9 100 % Driver.Packet 5557.2
43 450-461 6 1970.6 2078.0 2078.0 2078.0 225.8 100 % Driver.Packet 5583.1
44 461-472 5 1987.9 2512.9 2512.9 2512.9 325.8 100 % Driver.Packet 6024.3
45 472-484 6 2006.0 2445.9 2445.9 2445.9 227.4 100 % Driver.Packet 5862.1
46 484-495 6 1812.5 1872.1 1872.1 1872.1 272.2 100 % Driver.Packet 5212.2
47 495-506 6 1873.6 2029.9 2029.9 2029.9 271.1 100 % Driver.Packet 5472.6
48 506-516 5 2094.4 2210.6 2210.6 2210.6 271.3 100 % Driver.Packet 5873.3
49 516-528 6 1882.1 2155.9 2155.9 2155.9 317.3 100 % Driver.Packet 5489.5
50 528-539 6 1903.9 2163.3 2163.3 2163.3 271.2 100 % Driver.Packet 5452.0
51 539-549 5 2087.3 2167.1 2167.1 2167.1 276.1 100 % Driver.Packet 5794.3
52 549-559 5 1990.2 2288.7 2288.7 2288.7 273.7 100 % Driver.Packet 5863.7
53 559-570 5 2155.3 2236.7 2236.7 2236.7 217.3 100 % Driver.Packet 6155.3
54 570-581 5 1939.3 2820.5 2820.5 2820.5 272.1 100 % Driver.Packet 6478.1
55 581-593 6 1956.3 2409.4 2409.4 2409.4 317.8 100 % Driver.Packet 5899.0
56 593-603 5 1997.0 2214.2 2214.2 2214.2 268.1 100 % Driver.Packet 5925.2
57 603-615 5 2457.4 2716.7 2716.7 2716.7 270.6 100 % Driver.Packet 7026.8
58 615-627 6 1930.1 2174.2 2174.2 2174.2 269.0 100 % Driver.Packet 5688.9
59 627-637 5 1981.7 2434.8 2434.8 2434.8 269.6 100 % Driver.Packet 5890.8
60 637-648 5 2028.9 2148.9 2148.9 2148.9 269.2 100 % Driver.Packet 5887.1
61 648-658 5 2091.5 2325.2 2325.2 2325.2 266.6 100 % Driver.Packet 6050.3
62 658-668 5 2041.8 2190.5 2190.5 2190.5 268.4 100 % Driver.Packet 5887.3
63 668-679 5 1959.1 2757.2 2757.2 2757.2 215.0 100 % Driver.Packet 6343.8
64 679-691 6 1931.6 2174.7 2174.7 2174.7 268.8 100 % Driver.Packet 5626.2
65 691-703 6 1988.4 2200.3 2200.3 2200.3 313.8 100 % Driver.Packet 5658.6
66 703-713 5 2139.2 2261.9 2261.9 2261.9 277.0 100 % Driver.Packet 5987.8
67 713-724 5 2073.5 2587.6 2587.6 2587.6 269.4 100 % Driver.Packet 6328.3
68 724-736 5 2472.4 2702.4 2702.4 2702.4 216.5 100 % Driver.Packet 6889.9
69 736-748 5 2387.6 2618.4 2618.4 2618.4 273.9 100 % Driver.Packet 6837.1
70 748-759 5 2237.0 2506.8 2506.8 2506.8 326.5 100 % Driver.Packet 6592.6
71 759-771 6 2018.9 2651.7 2651.7 2651.7 273.1 100 % Driver.Packet 6025.4
72 771-783 5 2213.3 2593.7 2593.7 2593.7 272.7 100 % Driver.Packet 6505.4
73 783-793 5 2064.5 2389.0 2389.0 2389.0 218.6 100 % Driver.Packet 6186.9
74 793-805 5 2389.1 2631.0 2631.0 2631.0 328.2 100 % Driver.Packet 6824.1
75 805-816 5 2134.6 2771.1 2771.1 2771.1 273.1 100 % Driver.Packet 6553.5
76 816-827 5 2105.6 2288.9 2288.9 2288.9 272.6 100 % Driver.Packet 6009.6
77 827-837 5 2150.4 2192.3 2192.3 2192.3 218.1 100 % Driver.Packet 6117.5
78 837-848 5 2243.0 2389.1 2389.1 2389.1 331.3 100 % Driver.Packet 6397.5
79 848-860 6 1937.3 2245.8 2245.8 2245.8 226.2 100 % Driver.Packet 5775.8
80 860-872 6 1948.6 2133.2 2133.2 2133.2 318.1 100 % Driver.Packet 5582.7
81 872-882 5 2058.4 2242.6 2242.6 2242.6 270.6 100 % Driver.Packet 5908.4
82 882-892 5 2001.6 2232.5 2232.5 2232.5 218.5 100 % Driver.Packet 5881.7
83 892-903 5 2048.0 2261.1 2261.1 2261.1 331.4 100 % Driver.Packet 5828.3
84 903-913 5 1966.3 2740.1 2740.1 2740.1 274.4 100 % Driver.Packet 6264.3
85 913-924 5 2015.0 2227.3 2227.3 2227.3 218.2 100 % Driver.Packet 5889.5
86 924-934 5 1938.8 2303.6 2303.6 2303.6 325.3 100 % Driver.Packet 5847.3
87 934-944 5 2048.0 2698.3 2698.3 2698.3 216.1 100 % Driver.Packet 6198.3
88 944-955 5 2177.8 2262.7 2262.7 2262.7 324.7 100 % Driver.Packet 6170.3
89 955-967 5 2583.4 2809.4 2809.4 2809.4 277.4 100 % Driver.Packet 7026.0
90 967-978 4 2673.9 2955.3 2955.3 2955.3 204.9 100 % Driver.Packet 7536.3
91 978-988 4 2629.6 2655.9 2655.9 2655.9 271.5 100 % Driver.Packet 7274.3
92 988-998 5 2053.9 2113.3 2113.3 2113.3 269.4 100 % Driver.Packet 5841.5
93 998-1009 5 2245.5 2642.0 2642.0 2642.0 325.2 100 % Driver.Packet 6547.4
94 1009-1020 5 2122.2 2473.8 2473.8 2473.8 215.7 100 % Driver.Packet 6255.0
95 1020-1031 5 2140.6 2712.3 2712.3 2712.3 323.0 100 % Driver.Packet 6352.2
96 1031-1042 6 1959.6 2165.3 2165.3 2165.3 269.5 100 % Driver.Packet 5682.4
97 1042-1054 6 1945.9 2076.3 2076.3 2076.3 269.3 100 % Driver.Packet 5584.2
98 1054-1066 6 1931.1 2234.2 2234.2 2234.2 224.3 100 % Driver.Packet 5696.2
99 1066-1077 6 1876.9 2117.7 2117.7 2117.7 270.3 100 % Driver.Packet 5488.1
100 1077-1088 5 2083.3 2134.6 2134.6 2134.6 322.4 100 % Driver.Packet 5986.4
101 1088-1100 6 2001.1 2297.4 2297.4 2297.4 271.3 100 % Driver.Packet 5889.3
102 1100-1112 6 1899.5 2387.0 2387.0 2387.0 273.0 100 % Driver.Packet 5668.4
103 1112-1124 6 2016.8 2098.8 2098.8 2098.8 272.3 100 % Driver.Packet 5715.1
104 1124-1136 6 2056.9 2378.6 2378.6 2378.6 271.6 100 % Driver.Packet 5903.2
105 1136-1147 6 2000.4 2039.5 2039.5 2039.5 277.0 100 % Driver.Packet 5586.0
106 1147-1159 6 1813.0 2045.6 2045.6 2045.6 271.0 100 % Driver.Packet 5359.4
107 1159-1169 5 2195.7 2497.5 2497.5 2497.5 271.6 100 % Driver.Packet 6282.0
108 1169-1180 5 2226.8 2311.3 2311.3 2311.3 272.8 100 % Driver.Packet 6066.0
109 1180-1191 6 1901.4 2154.6 2154.6 2154.6 269.8 100 % Driver.Packet 5481.5
110 1191-1203 6 1907.5 2019.6 2019.6 2019.6 224.8 100 % Driver.Packet 5547.9
111 1203-1214 6 1796.5 2170.5 2170.5 2170.5 270.9 100 % Driver.Packet 5491.2
112 1214-1224 5 1975.8 2456.0 2456.0 2456.0 267.8 100 % Driver.Packet 5930.9
113 1224-1236 6 1958.2 2022.2 2022.2 2022.2 315.9 100 % Driver.Packet 5573.4
114 1236-1246 6 1757.4 1806.4 1806.4 1806.4 271.5 100 % Driver.Packet 4998.0
115 1246-1257 6 1786.2 1946.1 1946.1 1946.1 271.0 100 % Driver.Packet 5182.7
116 1257-1268 6 1836.4 1928.6 1928.6 1928.6 266.7 100 % Driver.Packet 5229.2
p99 ms  ....__......._.:@:::----::-::::--::::::::::--::::::-:--:-:-:-:-:::----------:-:::::-:--:---:---:::::--:-::--:::-::::  0-8182.9
gpu ms  ...___________::@---:=--:=:=--=:--=-=---=--=----=---:-=-------:-=--:-=--:=--:=-=-:=-:=:=-:--=:=----=------------=---  0-800.4
tools/trace_digest.py, A's first run (no bypass)

112 intervals, 0.0 to 1236.1 s, 2519 presents
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 3840x2160, commit 7bc49ce

# seconds presents p50 p90 p99 max GPU busy busiest worker largest phase
1 0-10 594 16.7 16.9 17.2 86.5 0.6 90 % Shader.ResolveGraphicsStagesAbi 64.3
2 10-20 600 16.7 16.9 17.0 17.3 0.6 90 % Shader.ResolveGraphicsStagesAbi 62.5
3 20-30 186 16.7 17.1 226.2 5382.6 4.8 89 % Shader.ResolveGraphicsStagesAbi 93.7
4 30-40 96 103.3 114.9 127.5 127.5 52.0 96 % Shader.ResolveGraphicsStagesAbi 464.9
5 40-51 74 112.5 203.2 511.2 511.2 55.8 94 % Shader.ResolveGraphicsStagesAbi 494.4
6 51-61 60 166.5 183.6 195.0 195.0 70.1 96 % Driver.Packet 475.7
7 61-71 65 152.9 168.0 180.1 180.1 69.5 96 % Driver.Packet 435.4
8 71-81 64 155.0 173.7 202.6 202.6 69.6 96 % Driver.Packet 441.8
9 81-91 64 154.9 173.0 185.9 185.9 69.5 96 % Driver.Packet 439.7
10 91-101 64 155.7 167.5 181.8 181.8 69.7 96 % Driver.Packet 438.2
11 101-111 62 160.2 167.8 255.2 255.2 70.8 96 % Driver.Packet 447.1
12 111-121 63 141.8 237.2 691.1 691.1 67.4 96 % Driver.Packet 351.3
13 121-132 29 317.0 522.4 995.6 995.6 110.6 98 % Shader.ResolveGraphicsStagesAbi 1566.5
14 132-146 20 301.8 1556.1 7136.6 7136.6 136.3 99 % Driver.Packet 1964.9
15 146-157 6 1872.1 2152.4 2152.4 2152.4 429.7 100 % Driver.Packet 5462.6
16 157-168 6 1765.4 2033.8 2033.8 2033.8 274.1 100 % Driver.Packet 5132.6
17 168-178 5 2098.2 2418.4 2418.4 2418.4 319.4 100 % Driver.Packet 6015.0
18 178-190 6 1959.5 2146.9 2146.9 2146.9 269.5 100 % Driver.Packet 5688.1
19 190-200 5 2137.3 2307.7 2307.7 2307.7 269.9 100 % Driver.Packet 6064.0
20 200-211 5 2022.7 2380.1 2380.1 2380.1 219.7 100 % Driver.Packet 6017.6
21 211-222 6 1866.9 2210.0 2210.0 2210.0 312.6 100 % Driver.Packet 5570.0
22 222-233 5 2080.6 2198.7 2198.7 2198.7 215.9 100 % Driver.Packet 5917.9
23 233-243 5 2084.1 2512.3 2512.3 2512.3 322.8 100 % Driver.Packet 6119.6
24 243-254 5 2134.1 2358.8 2358.8 2358.8 271.8 100 % Driver.Packet 6164.6
25 254-265 5 2284.3 2295.7 2295.7 2295.7 217.7 100 % Driver.Packet 6413.8
26 265-276 5 2140.8 2605.5 2605.5 2605.5 327.6 100 % Driver.Packet 6194.6
27 276-287 6 1995.1 2102.7 2102.7 2102.7 269.4 100 % Driver.Packet 5703.6
28 287-298 5 2148.5 2440.3 2440.3 2440.3 269.8 100 % Driver.Packet 6279.3
29 298-310 6 2010.0 2147.4 2147.4 2147.4 269.3 100 % Driver.Packet 5729.0
30 310-322 6 1931.8 2034.2 2034.2 2034.2 224.8 100 % Driver.Packet 5574.9
31 322-334 6 1989.0 2288.1 2288.1 2288.1 270.5 100 % Driver.Packet 5900.2
32 334-346 6 1948.3 2048.4 2048.4 2048.4 316.8 100 % Driver.Packet 5585.0
33 346-356 5 1994.4 2325.3 2325.3 2325.3 272.3 100 % Driver.Packet 5991.5
34 356-368 6 1971.0 2142.0 2142.0 2142.0 224.0 100 % Driver.Packet 5677.3
35 368-379 6 1886.1 2236.8 2236.8 2236.8 314.2 100 % Driver.Packet 5513.2
36 379-390 6 1878.0 1935.8 1935.8 1935.8 225.4 100 % Driver.Packet 5337.4
37 390-402 6 1928.5 2160.3 2160.3 2160.3 269.4 100 % Driver.Packet 5697.6
38 402-413 6 1902.8 1949.6 1949.6 1949.6 269.1 100 % Driver.Packet 5471.0
39 413-424 5 2079.5 2165.6 2165.6 2165.6 266.5 100 % Driver.Packet 5860.9
40 424-436 6 1941.0 2385.3 2385.3 2385.3 313.6 100 % Driver.Packet 5833.4
41 436-446 5 2091.6 2329.5 2329.5 2329.5 270.3 100 % Driver.Packet 6202.1
42 446-458 5 2426.2 2428.8 2428.8 2428.8 216.1 100 % Driver.Packet 6498.4
43 458-469 5 2314.2 2387.8 2387.8 2387.8 276.0 100 % Driver.Packet 6700.9
44 469-481 5 2132.1 2661.0 2661.0 2661.0 269.6 100 % Driver.Packet 6631.7
45 481-492 5 2272.5 2429.0 2429.0 2429.0 269.8 100 % Driver.Packet 6402.9
46 492-503 5 2210.7 2513.0 2513.0 2513.0 324.6 100 % Driver.Packet 6557.4
47 503-514 5 2110.7 2470.3 2470.3 2470.3 217.2 100 % Driver.Packet 6251.7
48 514-525 5 2176.2 2327.2 2327.2 2327.2 327.2 100 % Driver.Packet 6287.0
49 525-536 5 2221.1 2411.6 2411.6 2411.6 272.4 100 % Driver.Packet 6442.7
50 536-547 5 2162.3 2646.6 2646.6 2646.6 271.5 100 % Driver.Packet 6540.5
51 547-557 5 2110.0 2170.3 2170.3 2170.3 214.0 100 % Driver.Packet 6079.5
52 557-568 5 2130.9 2274.1 2274.1 2274.1 327.3 100 % Driver.Packet 6166.0
53 568-579 5 2097.0 2700.1 2700.1 2700.1 269.2 100 % Driver.Packet 6403.2
54 579-590 5 2347.2 2395.6 2395.6 2395.6 218.8 100 % Driver.Packet 6533.2
55 590-602 5 2232.9 2494.8 2494.8 2494.8 270.1 100 % Driver.Packet 6511.4
56 602-613 5 2103.5 2459.1 2459.1 2459.1 324.7 100 % Driver.Packet 6344.0
57 613-623 5 2092.9 2263.6 2263.6 2263.6 272.0 100 % Driver.Packet 6141.6
58 623-634 5 2025.9 2312.0 2312.0 2312.0 272.1 100 % Driver.Packet 6121.1
59 634-644 5 1964.9 2219.8 2219.8 2219.8 214.6 100 % Driver.Packet 5885.5
60 644-654 5 2086.4 2159.7 2159.7 2159.7 270.1 100 % Driver.Packet 5853.6
61 654-665 5 2114.4 2812.7 2812.7 2812.7 324.1 100 % Driver.Packet 6685.7
62 665-676 5 2029.3 2186.0 2186.0 2186.0 212.6 100 % Driver.Packet 5964.3
63 676-686 5 2062.1 2382.6 2382.6 2382.6 266.0 100 % Driver.Packet 6109.7
64 686-698 5 2371.1 2449.0 2449.0 2449.0 268.2 100 % Driver.Packet 6599.0
65 698-708 5 2074.7 2226.4 2226.4 2226.4 319.5 100 % Driver.Packet 6107.1
66 708-719 5 2061.7 2257.2 2257.2 2257.2 266.5 100 % Driver.Packet 6064.9
67 719-730 5 2090.4 2533.7 2533.7 2533.7 268.2 100 % Driver.Packet 6566.1
68 730-741 5 2116.3 2374.6 2374.6 2374.6 267.0 100 % Driver.Packet 6185.1
69 741-751 4 2823.7 2883.0 2883.0 2883.0 203.4 100 % Driver.Packet 7583.5
70 751-762 4 2854.6 3062.0 3062.0 3062.0 337.7 100 % Driver.Packet 8081.3
71 762-774 4 3214.1 3624.8 3624.8 3624.8 277.0 100 % Driver.Packet 8751.4
72 774-784 4 2603.4 2960.4 2960.4 2960.4 271.6 100 % Driver.Packet 7452.9
73 784-795 4 2564.6 2779.2 2779.2 2779.2 205.1 100 % Driver.Packet 7350.5
74 795-807 5 2432.6 3022.1 3022.1 3022.1 272.7 100 % Driver.Packet 7407.2
75 807-820 4 3101.9 3287.6 3287.6 3287.6 344.9 100 % Driver.Packet 8846.0
76 820-831 4 2926.8 3662.5 3662.5 3662.5 274.8 100 % Driver.Packet 8649.4
77 831-842 4 2612.8 2665.3 2665.3 2665.3 280.3 100 % Driver.Packet 7515.2
78 842-852 4 2482.7 3128.8 3128.8 3128.8 274.8 100 % Driver.Packet 7510.2
79 852-863 4 2728.7 2817.0 2817.0 2817.0 207.5 100 % Driver.Packet 7783.2
80 863-873 4 2962.8 3001.7 3001.7 3001.7 274.3 100 % Driver.Packet 7716.6
81 873-885 5 2459.0 2499.3 2499.3 2499.3 330.6 100 % Driver.Packet 6909.7
82 885-895 4 2655.2 2929.3 2929.3 2929.3 276.2 100 % Driver.Packet 7337.3
83 895-908 5 2471.5 2533.8 2533.8 2533.8 275.2 100 % Driver.Packet 7087.4
84 908-918 4 2704.6 3058.1 3058.1 3058.1 206.5 100 % Driver.Packet 7557.1
85 918-929 5 2284.3 2442.1 2442.1 2442.1 331.4 100 % Driver.Packet 6619.1
86 929-940 4 2659.5 3103.6 3103.6 3103.6 205.5 100 % Driver.Packet 7971.4
87 940-951 4 2462.6 3427.4 3427.4 3427.4 274.4 100 % Driver.Packet 7641.4
88 951-963 5 2450.1 2811.7 2811.7 2811.7 274.5 100 % Driver.Packet 7255.1
89 963-976 5 2209.2 3382.1 3382.1 3382.1 273.0 97 % Driver.Packet 7332.5
90 976-987 4 2822.3 2876.6 2876.6 2876.6 294.9 100 % Driver.Packet 7698.6
91 987-997 4 2584.8 2601.7 2601.7 2601.7 342.4 100 % Driver.Packet 7337.5
92 997-1008 5 2102.0 2207.4 2207.4 2207.4 217.5 100 % Driver.Packet 6161.8
93 1008-1019 4 2982.2 3000.9 3000.9 3000.9 342.5 99 % Driver.Packet 8282.3
94 1019-1030 4 2669.3 3340.0 3340.0 3340.0 278.4 100 % Driver.Packet 7736.0
95 1030-1040 4 2741.9 2880.6 2880.6 2880.6 274.4 100 % Driver.Packet 7328.9
96 1040-1050 4 2907.2 3156.0 3156.0 3156.0 274.0 100 % Driver.Packet 7568.9
97 1050-1062 4 2989.0 3511.9 3511.9 3511.9 275.4 99 % Driver.Packet 8798.0
98 1062-1075 5 2254.8 2935.4 2935.4 2935.4 272.2 100 % Driver.Packet 7090.6
99 1075-1087 5 2297.6 2926.9 2926.9 2926.9 214.7 100 % Driver.Packet 7065.0
100 1087-1098 5 2363.7 2457.9 2457.9 2457.9 327.2 100 % Driver.Packet 6746.1
101 1098-1116 5 2082.3 9651.1 9651.1 9651.1 268.8 100 % Driver.Packet 10507.7
102 1116-1127 3 2848.1 4938.1 4938.1 4938.1 270.5 100 % Driver.Packet 10011.6
103 1127-1137 5 2103.5 2292.8 2292.8 2292.8 266.3 100 % Driver.Packet 6115.0
104 1137-1149 5 2195.7 2733.3 2733.3 2733.3 215.3 99 % Driver.Packet 6737.1
105 1149-1159 5 2080.5 2266.2 2266.2 2266.2 321.2 100 % Driver.Packet 6129.1
106 1159-1170 5 2101.9 2145.9 2145.9 2145.9 213.7 100 % Driver.Packet 5961.2
107 1170-1180 5 2030.2 2725.8 2725.8 2725.8 267.4 100 % Driver.Packet 6234.1
108 1180-1193 4 3153.2 4013.1 4013.1 4013.1 336.4 100 % Driver.Packet 9063.8
109 1193-1203 3 3121.5 4497.1 4497.1 4497.1 273.5 100 % Driver.Packet 10035.7
110 1203-1215 5 2128.6 3364.7 3364.7 3364.7 267.7 100 % Driver.Packet 6756.7
111 1215-1226 5 2101.0 2528.6 2528.6 2528.6 266.6 100 % Driver.Packet 6224.6
112 1226-1236 5 2120.3 2197.7 2197.7 2197.7 269.1 100 % Driver.Packet 6013.2
p99 ms  ...........__#::::::::::::::::::::::::::::::::::::::-:::::::-:::::::--------:---:-:-:-----::-------:@+:-::-==-::  0-9651.1
gpu ms  ..._________:-@*#**+#+#*+#***+*#*+#+***#*+***#+#**=#*+*#**=*#=**#***=#**=*#***=*#**=#=****#+#*****=#***+#=*#****  0-429.7

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@adriadam10 on the test cost: 1679477 draws only the lookups whose outcome each case checks and notes the rest of each 2,048-lookup window on the driver's bypass. The cold-scene case keeps its 1,000-draw scene, which is still red on the head before the warm-up fix. With the validation layers on GitHub's llvmpipe runner, the four tests now take 2.87, 2.83, 1.16 and 1.04 s, against 18.78, 19.13, 17.45 and 10.47 s before. No check was dropped: the 4,096-draw lengthening and the window of hits that ends a run are in LowWindowsLengthenTheBypass, and Tested lists where each one now lives. No production code changed.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@adriadam10 on the benefit: a profiled boot of 14209e9 on Resident Evil Village (PPSA01556)'s menu (not a timing run) bypassed draws in only 9 of its 80 ten-second blocks, 112,640 draws in all, while 331,056 of its 331,072 lookups found no entry and the byte budget evicted 33,539 entries. A pair on a variant where a second sighting of a key the budget evicted no longer counts as useful, with the cold-scene case still green, is queued, and its result will go into Tested. The commonparent VUID is being checked against main on llvmpipe, and I'll answer it on its own.

@TechLevelZero

TechLevelZero commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 1679477 merged onto main f6fddd6 · tested 2026-10-30 06:20 UTC · 28 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,346 passed · 3 failed (0 new, 2 also fail on main, 1 unstable on main) · 41 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,390 of 2,950 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (906 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_draw_cache_cold_scene_off 94.8 s, ⚠️ agc_driver_draw_cache_cold_scene 93.3 s, ⚠️ agc_driver_bda_device 78.9 s, ⚠️ agc_driver_depth_clear_hle 30.4 s
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_submit_progress: failed in 5 of the last 7 main runs
Failing on main too (2, not counted against this PR)
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (4, not in the main baseline's validation pass)
agc_driver_draw_cache_cold_scene
agc_driver_draw_cache_cold_scene_off
agc_driver_draw_cache_low_hit_bypass
agc_driver_draw_cache_low_hit_bypass_off
Validation IDs already present on main (4 IDs in 428 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (428 tests): agc_compute_pipeline_replay, agc_driver, agc_driver_address_passes, agc_driver_address_passes_draw_transitions, agc_driver_address_passes_targets_split, agc_driver_alias_copy_label, agc_driver_array_layer_target_cpu, agc_driver_bda_span_reads_draw_pipeline, and 420 more
VUID-vkCmdCopyImage-srcImage-01548 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 3 more
VUID-vkCmdCopyImage-srcImage-01551 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 3 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
Skipped (41)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_msaa_dcc_compared_import_2: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_4: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_8: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_stencil_ref_export: skipped, the device lacks VK_EXT_shader_stencil_export
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_fresh: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or plat
Reproduce
git fetch origin 167947744aff84d8c890b9c4ef349bae799283a1 f6fddd60d826831f70f7c62e25423610ee742bcc
git checkout f6fddd60d826831f70f7c62e25423610ee742bcc && git merge --no-ff 167947744aff84d8c890b9c4ef349bae799283a1
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@MarcZX10 @adriadam10 on VUID-vkCmdCopyBuffer-commonparent in agc_driver_depth_clear_hle: it hasn't repeated on this PR's code.

  • NVIDIA: TechLevelZero's run on 1679477 (report), merged onto the same main f6fddd6 as the earlier report, shows no new validation IDs in 906 GPU tests. agc_driver_depth_clear_hle there shows only main's VUID-vkCmdCopyImage-srcImage-01548 and -01551. 1679477 changes only DrawCacheReuse.cpp, so its driver code is the same as 05d2faa's.
  • llvmpipe (VK_LAYER_KHRONOS_validation on GitHub's Linux runner, run): main 08a10d2 against this PR merged with it. agc_driver_depth_clear_hle, agc_driver_depth_fast_clear and agc_driver_depth_fast_clear_submit ran once on main and three times with the change, and all passed. Neither arm has a commonparent message, and both show the same three VUIDs: VUID-VkDeviceCreateInfo-pNext-pNext and the two vkCmdCopyImage ones main already shows.
  • What the earlier log shows: a copy between buffers of two devices. The test opens its own device, and late in that run the driver created a second one. This PR changes neither device creation nor any buffer path: its production diff is the draw-cache bypass, DrawCacheBypass and its Skip() and Note() calls around the lookup. So I read the earlier report as an intermittent problem in that test's two-device setup, not something this change causes.

@ntamas94

Copy link
Copy Markdown
Contributor

Crysis Remastered (CUSA18659) on AnyPS5 is exactly the low-hit-rate case this guards against. Profiled with APS5_PROFILE_DRAW=1 on a steady scene (per 10 s): 110,316 of 113,365 draw-cache lookups are "no entry" and only 2,349 hit (~2%), while the per-draw prepare (capture 33 µs + recompile 17.5 µs) dominates a 70.8 µs/draw frame at ~7-9 FPS.

The underlying cause is the draw key mixing the game's per-frame-moving constant-buffer pointers (#5609 territory), but until that lands, skipping the lookup/insert under 5% would cut the wasted cache work here. Confirmed it is key churn, not eviction: at APS5_DRAW_CACHE_ENTRIES=65536 the table reached 62,176 entries with 0 evictions and the miss rate held. A useful fallback.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-checked — new head, changes still needed

The atomic window-state fix addresses the earlier race, but the updated performance change still lacks a matched capture pair for the reviewed head against current main.

What I ran

Reviewed head 167947744aff84d8c890b9c4ef349bae799283a1. GitHub reports the PR base snapshot as 76fd1c09e9be0465d50a7431a79d371a5a10abb2; current upstream main is 8f756acf599027be651dadb392506dbbd4b785e9. The read-only merge preview onto current main was clean (23003b378c7cbbcc136f8388348fc38d7d25c8f4). Environment: Linux x86_64, Python 3.11.2, GCC 12.2.0. No build or test executable was run.

git diff --check 8f756acf599027be651dadb392506dbbd4b785e9...167947744aff84d8c890b9c4ef349bae799283a1
python3 tools/check_conventions.py --base 8f756acf599027be651dadb392506dbbd4b785e9 --head 167947744aff84d8c890b9c4ef349bae799283a1
python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 12478
git merge-tree --write-tree 8f756acf599027be651dadb392506dbbd4b785e9 167947744aff84d8c890b9c4ef349bae799283a1

Results

Check Result
Patch whitespace Passed
Conventions and PR template Passed against current main
Current-main merge preview Clean
Draw-cache window update The reviewed code now keeps window counts, low-window streak and bypass count in one compare-exchange state; this resolves the previously reported stale streak update. The new concurrency test exercises simultaneous window closures.
No-build precheck Stable head/base; conventions and mergeability passed. Its ABI and test-quality helper steps could not run in the isolated PR copy because those helper scripts are local-only; they are not relevant to this change's ABI.
Hosted checks Windows passed; Linux and specialized jobs were skipped in the last status snapshot. A separate NVIDIA report covers this head merged onto main f6fddd6, not current main 8f756acf.
Performance evidence The latest Crysis comment reports one PR-side profile. It has no matched main capture, summary-line pair, attached traces, or trace digests for this head. Existing Village captures in the description are from older code; the description says the pair for the warm-up-fixed branch was queued.
Local build/tests Not run
Unedited output from local checks
All conventions checks passed.
23003b378c7cbbcc136f8388348fc38d7d25c8f4

git diff --check exited 0 with no output.

The isolated precheck reported these helper errors:

/usr/bin/python3: can't open file '/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-12478-167947744aff/head-167947744aff-d880e2d9/tools/pr_abi_audit.py': [Errno 2] No such file or directory
/usr/bin/python3: can't open file '/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-12478-167947744aff/head-167947744aff-d880e2d9/tools/pr_test_quality.py': [Errno 2] No such file or directory

Findings

Blocking

  • The performance evidence does not measure the current change against current main. The latest Crysis profile is useful evidence that a low-hit workload exists, but it reports only the changed build. The older comparison predates the warm-up and atomic window-order fixes. Since this is a perf PR and the branch still describes the bypass as cutting wasted work, please capture current main and this exact head on the same machine, title, scene, and settings. Add both aps5-summary.jsonl lines, attach both traces, and include tools/trace_digest.py output for each trace.

Non-blocking

  • The reported NVIDIA and Windows checks are useful, but the NVIDIA run used a f6fddd6 integration rather than current main; the local merge preview establishes clean application, not test coverage of that integration.
  • The new concurrency test is a stress test rather than a demonstrated negative control: the PR description says it also passes on the parent of the atomic fix. I inspected the single-state compare-exchange source change, but the test did not demonstrate that it catches the old race.

Sources

Not verified

  • I did not build or run draw-cache tests, validation layers, console/title behavior, or performance captures locally.
  • I did not reproduce the author/community-reported Linux or NVIDIA results.

To get this to a good state

Add the matched current-main/current-head capture pair, both summary lines, traces and digest output. I will rerun the same source checks and review the new evidence against the resulting head.

The cold-scene case drew a scene of 1000 new draws for four frames,
4000 draws that each miss or hit the draw cache. On an NVIDIA device
with the validation layer on that took about 94 s per arm. Under the
two-low-windows rule the 1000-draw scene also no longer depended on
the warm-up: its first window held 48 hits and its second was useful,
so it stayed green with the warm-up taken out.

The case now notes one low window on the driver's bypass, as the
stage-hit case does, then draws a scene of 128 new draws for four
frames and closes the window after the second frame. With the warm-up
the window holds the scene's 128 second sightings, more than the 103
useful lookups of 5% of 2048, so the run of low windows ends and the
fourth frame hits. Without it, that window is the second low one in a
row, the bypass starts and the fourth frame hits none. The assertion
(at least 90% hits in the fourth frame), the frame count and the
bypass-off arm are unchanged; on lavapipe each arm goes from about
0.9 s to 0.2 s, and from 2.3 s to 0.5 s with the validation layer.
@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

The tools/trace_digest.py output for the two captures of the Resident Evil Village (PPSA01556) pair on main 6472c70: A is main plus #11580 and #10304 (237e88d), and B is the same with 1679477 merged (05bae01). The description's Tested section has the pair, the summary lines and the traces.

A (237e88d, main 6472c70 + #11580 + #10304): tools/trace_digest.py

seconds 960:30 from present 2821: 22 presents, frame p50 1400.9 / p90 1708.7 / p99 1985.6 / max 1985.6 ms, GPU busy 248.4 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 3840x2160, commit 237e88d (dirty), dropped: no

{"commit":"237e88d4ff9c","dirty":true,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":2821,"ms":31663.912},"presents":22,"frame_ms":{"p50":1400.899,"p90":1708.722,"p99":1985.646,"max":1985.646},"gpu_busy_ms_per_present":248.362,"worker_busy_pct":{"queue worker 0x0":99.512,"queue worker 0x38":0.083,"queue worker 0x28":93.381,"queue worker 0x20":88.858},"top_phases_ms_per_frame":{"Driver.Packet":4051.385,"Driver.Packet.memory_wait":2363.248,"Driver.Packet.draw":1064.743,"Driver.Draw":1063.573,"Graphics.Draw":834.753,"Graphics.Draw.draw_and_resource_release":812.4,"Driver.Packet.dispatch":565.972,"Driver.Dispatch":515.708},"trace_dropped":false,"trace":"aps5-trace-237e88d4ff9c-28876.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 2841: 1985.6 ms at 27970 ms: Driver.WorkerWait (queue worker 0x38) 1984.3, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1978.2, Driver.Packet (queue worker 0x0) 1965.3, Driver.Packet (queue worker 0x28) 1886.1
  • present 2840: 1712.7 ms at 26257 ms: Driver.WorkerWait (queue worker 0x38) 1711.5, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1707.4, Driver.Packet (queue worker 0x0) 1695.7, Driver.Packet (queue worker 0x28) 1602.6
  • present 2842: 1708.7 ms at 29955 ms: Driver.Packet (queue worker 0x0) 1688.5, Driver.Packet (queue worker 0x28) 1599.0, Driver.Packet.memory_wait (queue worker 0x28) 1579.3, Driver.Packet (queue worker 0x20) 1521.6
  • present 2822: 1602.9 ms at 1520 ms: Driver.WorkerWait (queue worker 0x38) 1599.2, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1594.4, Driver.Packet (queue worker 0x0) 1584.1, Driver.Packet (queue worker 0x28) 1522.5
  • present 2831: 1575.9 ms at 13807 ms: Driver.WorkerWait (queue worker 0x38) 1574.6, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1568.3, Driver.Packet (queue worker 0x0) 1555.7, Driver.Packet (queue worker 0x28) 1485.2

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 1037.3 (72 %) 387.8 (27 %) 14.2 92.5 Driver.Packet 1421.1
draw committer 656.0 (46 %) 42.5 (3 %) 740.8 4.7 Graphics.Draw 670.9, Recorder.Submit 2.0
queue worker 0x38 1.0 (0 %) 1291.7 (90 %) 146.5 0.8 Driver.Packet 1.0, Driver.EndSubmission 0.1
presenter 3.4 (0 %) 1.4 (0 %) 1434.4 0.1 VideoOut.Flip 3.4, Driver.Present 1.5
queue worker 0x28 18.4 (1 %) 1409.2 (98 %) 11.7 0.2 Driver.Packet 1343.5, Driver.EndSubmission 0.4
queue worker 0x20 131.7 (9 %) 1297.8 (90 %) 9.7 5.1 Driver.Packet 1273.8, Driver.EndSubmission 4.3
gpu 248.2 (17 %) 0.0 (0 %) 1191.1 0.0 batch 248.2

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 4039.4, Driver.Packet.memory_wait 2363.0, Driver.WorkerWait 1530.2, Driver.WorkerWait.dequeue_order 1286.8, Driver.Packet.draw 1063.9, Driver.Draw 1062.8, Graphics.Draw 834.1, Graphics.Draw.draw_and_resource_release 811.6, Driver.Packet.dispatch 564.9, Driver.Dispatch 514.5

Longest waits

  • Driver.WorkerWait (queue worker 0x38) 1984.3 ms at 27971 ms, present 2841
  • Driver.WorkerWait (queue worker 0x38) 1711.5 ms at 26258 ms, present 2840
  • Driver.Packet.memory_wait (queue worker 0x28) 1695.4 ms at 28146 ms, present 2841
  • Driver.WorkerWait (queue worker 0x38) 1599.9 ms at 1524 ms, present 2822
  • Driver.WorkerWait (queue worker 0x38) 1574.5 ms at 13809 ms, present 2831
  • Driver.WorkerWait (queue worker 0x38) 1545.6 ms at 23311 ms, present 2838
  • Driver.WorkerWait (queue worker 0x38) 1538.8 ms at 12268 ms, present 2830
  • Driver.Packet.memory_wait (queue worker 0x20) 1499.2 ms at 28118 ms, present 2841
  • Driver.WorkerWait (queue worker 0x38) 1495.9 ms at 15385 ms, present 2832
  • Driver.Packet.memory_wait (queue worker 0x28) 1447.9 ms at 26394 ms, present 2840

Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)

  • batch 720: 41.9 ms at 17034 ms, present 2833: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 2.5, Driver.Packet.dispatch (queue worker 0x0) 2.3, Driver.Dispatch (queue worker 0x0) 2.2, Vulkan.DispatchRecipe (queue worker 0x0) 1.2
  • batch 189: 41.5 ms at 4543 ms, present 2824: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.5, Driver.Packet.dispatch (queue worker 0x0) 0.3, Driver.Dispatch (queue worker 0x0) 0.3, Driver.Packet.flush_between_packets (queue worker 0x0) 0.1
  • batch 660: 41.4 ms at 15512 ms, present 2832: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 2.1, Driver.Packet.dispatch (queue worker 0x0) 1.8, Driver.Dispatch (queue worker 0x0) 1.8, Vulkan.DispatchRecipe (queue worker 0x0) 0.8
  • batch 131: 41.4 ms at 3265 ms, present 2823: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.2, Driver.Packet.dispatch (queue worker 0x0) 0.2, Driver.Dispatch (queue worker 0x0) 0.2, Driver.Packet.flush_between_packets (queue worker 0x0) 0.1
  • batch 308: 41.1 ms at 7242 ms, present 2826: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.4, Driver.Packet.dispatch (queue worker 0x0) 0.3, Driver.Dispatch (queue worker 0x0) 0.3, Driver.Packet.flush_between_packets (queue worker 0x0) 0.1
B (05bae01, A + 1679477): tools/trace_digest.py

seconds 960:30 from present 2834: 22 presents, frame p50 1358.3 / p90 1505.0 / p99 1681.0 / max 1681.0 ms, GPU busy 237.4 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 3840x2160, commit 05bae01 (dirty), dropped: no

{"commit":"05bae016f8dd","dirty":true,"env":{"APS5_HOST_IMPORT_MIB":"6400","APS5_LAZY_SHADER_PREPARE":"1","APS5_NO_GPL":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_SECONDS":"960:30"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","cpu":"AMD Ryzen 9 5900HS with Radeon Graphics","cpu_threads":16,"memory_mib":15776,"title_id":"PPSA01556","title":"Resident Evil Village","content_version":"01.210.000","resolution":"3840x2160","window":{"spec":"seconds 960:30","first_present":2834,"ms":30167.48},"presents":22,"frame_ms":{"p50":1358.259,"p90":1505.007,"p99":1680.983,"max":1680.983},"gpu_busy_ms_per_present":237.445,"worker_busy_pct":{"queue worker 0x0":99.552,"queue worker 0x38":0.053,"queue worker 0x20":89.735,"queue worker 0x28":94.132},"top_phases_ms_per_frame":{"Driver.Packet":3883.824,"Driver.Packet.memory_wait":2284.046,"Driver.Packet.draw":1054.258,"Driver.Draw":1053.291,"Graphics.Draw":846.766,"Graphics.Draw.draw_and_resource_release":828.217,"Driver.Packet.dispatch":505.62,"Driver.Dispatch":445.217},"trace_dropped":false,"trace":"aps5-trace-05bae016f8dd-11428.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 2846: 1681.0 ms at 15979 ms: Driver.WorkerWait (queue worker 0x38) 1680.3, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1675.4, Driver.Packet (queue worker 0x0) 1663.8, Driver.Packet (queue worker 0x28) 1598.0
  • present 2852: 1567.5 ms at 24471 ms: Driver.WorkerWait (queue worker 0x38) 1566.7, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1560.5, Driver.Packet (queue worker 0x0) 1549.3, Driver.Packet (queue worker 0x28) 1483.2
  • present 2853: 1505.0 ms at 26039 ms: Driver.WorkerWait (queue worker 0x38) 1503.8, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1497.0, Driver.Packet (queue worker 0x0) 1487.6, Driver.Packet (queue worker 0x28) 1427.9
  • present 2847: 1500.3 ms at 17660 ms: Driver.WorkerWait (queue worker 0x38) 1499.4, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1493.0, Driver.Packet (queue worker 0x0) 1482.8, Driver.Packet (queue worker 0x28) 1424.0
  • present 2848: 1477.0 ms at 19161 ms: Driver.WorkerWait (queue worker 0x38) 1475.9, Driver.WorkerWait.dequeue_order (queue worker 0x38) 1469.3, Driver.Packet (queue worker 0x0) 1461.5, Driver.Packet (queue worker 0x28) 1401.6

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 990.9 (72 %) 367.7 (27 %) 12.7 93.0 Driver.Packet 1354.8, Driver.Completion 0.0
draw committer 601.2 (44 %) 53.1 (4 %) 716.9 5.8 Graphics.Draw 615.0, Recorder.Submit 2.2
presenter 3.3 (0 %) 0.3 (0 %) 1367.7 0.1 VideoOut.Flip 3.3, Driver.Present 0.3
queue worker 0x38 0.6 (0 %) 1251.1 (91 %) 119.5 0.8 Driver.Packet 0.5, Driver.EndSubmission 0.1
queue worker 0x20 109.2 (8 %) 1254.1 (91 %) 8.0 5.1 Driver.Packet 1227.0, Driver.EndSubmission 2.8
queue worker 0x28 18.0 (1 %) 1343.9 (98 %) 9.4 0.2 Driver.Packet 1290.4, Driver.EndSubmission 0.4
gpu 248.8 (18 %) 0.0 (0 %) 1122.4 0.0 batch 248.8

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 3872.8, Driver.Packet.memory_wait 2283.9, Driver.WorkerWait 1459.0, Driver.WorkerWait.dequeue_order 1245.9, Driver.Packet.draw 1053.3, Driver.Draw 1052.3, Graphics.Draw 845.8, Graphics.Draw.draw_and_resource_release 827.1, Driver.Packet.dispatch 504.1, Driver.Dispatch 443.5

Longest waits

  • Driver.WorkerWait (queue worker 0x38) 1680.6 ms at 15980 ms, present 2846
  • Driver.WorkerWait (queue worker 0x38) 1566.6 ms at 24472 ms, present 2852
  • Driver.WorkerWait (queue worker 0x38) 1503.9 ms at 26040 ms, present 2853
  • Driver.WorkerWait (queue worker 0x38) 1499.3 ms at 17662 ms, present 2847
  • Driver.Packet.memory_wait (queue worker 0x28) 1483.0 ms at 16078 ms, present 2846
  • Driver.WorkerWait (queue worker 0x38) 1475.7 ms at 19162 ms, present 2848
  • Driver.WorkerWait (queue worker 0x38) 1465.6 ms at 2486 ms, present 2836
  • Driver.WorkerWait (queue worker 0x38) 1436.9 ms at 11989 ms, present 2843
  • Driver.WorkerWait (queue worker 0x38) 1431.8 ms at 9198 ms, present 2841
  • Driver.WorkerWait (queue worker 0x38) 1363.3 ms at 23108 ms, present 2851

Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)

  • batch 1111: 41.6 ms at 26167 ms, present 2853: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 1.2, Driver.Packet.dispatch (queue worker 0x0) 1.0, Driver.Dispatch (queue worker 0x0) 1.0, Vulkan.DispatchRecipe (queue worker 0x0) 0.4
  • batch 702: 41.6 ms at 16081 ms, present 2846: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.2, Driver.Packet.dispatch (queue worker 0x0) 0.1, Driver.Dispatch (queue worker 0x0) 0.1, Vulkan.DispatchRecipe (queue worker 0x0) 0.1
  • batch 589: 41.5 ms at 13535 ms, present 2844: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.1, Driver.Packet.flush_between_packets (queue worker 0x0) 0.0, Driver.Packet.dispatch (queue worker 0x0) 0.0, Driver.Dispatch (queue worker 0x0) 0.0
  • batch 533: 41.4 ms at 12111 ms, present 2843: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.4, Driver.Packet.dispatch (queue worker 0x0) 0.3, Driver.Dispatch (queue worker 0x0) 0.2, Vulkan.DispatchRecipe (queue worker 0x0) 0.1
  • batch 1171: 41.4 ms at 27681 ms, present 2854: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 0.3, Driver.Packet.dispatch (queue worker 0x0) 0.2, Driver.Dispatch (queue worker 0x0) 0.2, Driver.Packet.flush_between_packets (queue worker 0x0) 0.1

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@adriadam10 @MarcZX10 on your reviews of 1679477. This head, eaafdf9, changes only the test (DrawCacheReuse.cpp, +6 −3). The pair below ran on 1679477's library code.

The test cost.

  • The cold-scene case now notes one low window, then draws a 128-draw scene for 4 frames: 512 draws per arm instead of 4,000. On lavapipe with the validation layer, each arm takes 0.47 s against 2.3 s before.
  • On NVIDIA they took 93–95 s on 1679477. We'd estimate about 12 s now; your bot's run on this head will measure it.
  • The cut also restores a red the old case had lost. Under the two-low-windows rule, the 1,000-draw scene stayed green with the warm-up removed. Now the case fails with the warm-up removed, and its _off arm fails when the switch is also ignored. It also fails when the bypass starts after a single low window.
  • ×10 on GitHub: Linux 15 of 15 pass. On Windows all 15 skip, since the runner has no Vulkan device.

The benefit.

  • The pair: Resident Evil Village (PPSA01556), main 6472c70 against the same tree with 1679477 merged, B A A B, unprofiled, one shader-cache key, GPU clocks not held.
    • B ran 0.666 and 0.660 fps, A 0.588 and 0.583: +13.3%.
    • The captures follow the form: A then B in one session, both summary lines, the traces and their trace_digest.py output (in this comment). They're in the description's Tested section, with the trees' commits on the fork.
  • We don't attribute that gain to this change.
    • In a profiled boot of the PR's tree, the bypass started in 0 of the measured window's 57 ten-second blocks. Its 12 starts were all during loading.
    • At that menu, both trees' profiled boots hit 0 times, with the cache full at 255 of 256 MiB.
    • With the bypass off, the head does no less work per draw than main.
    • So the description now claims no speed gain. The pair on 14209e9 found none either.
  • Why the bypass doesn't start there: every lookup at that menu finds no entry, so a window's useful lookups can only be sightings of draw keys seen before. The warm-up rule counts those, and they keep every window above 5%.

Offered, not pushed: fe3387b, on fork branch fix/12478-no-hit-window-low, on top of eaafdf9.

  • What it does: a window counts as low when none of its lookups was a whole-draw hit, a verify hit or a stage reused through data candidates, so sightings alone no longer hold a window out of the run.
  • Tested on lavapipe: a new agc_driver_draw_cache_sightings_bypass fails 20 of 20 on eaafdf9 and passes 20 of 20 with it. agc_driver_draw_cache_rare_hits (about 1% real hits) and StageHitsKeepTheCacheLookedUp stay looked up.
  • Not measured in a game, so we make no claim for it. It's there if you want it.

The VUID-vkCmdCopyBuffer-commonparent in agc_driver_depth_clear_hle on the earlier NVIDIA run is #10791, which comes from main. The driver's idle store records another device's pending buffers on its own command buffer when one process has two live devices. TechLevelZero's #10940, still open, fixes it. The runs on 1679477 didn't show it.

We'll go with your call on the PR's direction. Could you both take another look at this head?

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cold-scene test change is fine: 128 draws after one noted low window, and it is red when the warm-up is removed. The library code is the same as 1679477, which I already read. One point still blocks this, unchanged from the last two reviews:

  • No benefit shown. The description says the current head has no measurable gain. In the Resident Evil Village boot the bypass starts in none of the 57 measured blocks, and in Planet of Lana in none, so the +13.3% pair isn't attributable to this change. The change adds a window, an env var and counters on the draw path, so it needs one scene where the bypass fires under the "seen before counts as useful" rule and the gain is outside noise. Please post a main / change pair from the same machine and scene with the aps5-summary.jsonl lines and tools/trace_digest.py output, plus the [draw-cache] bypassed lines showing it fired during the measured window. @ntamas94's Crysis Remastered profile (~2% hits, 110k of 113k lookups "no entry") or the Red Dead Redemption case from #5404 are candidates. If no scene fires and helps, the direction is to drop the change.

@MarcZX10's VUID-vkCmdCopyBuffer-commonparent question in agc_driver_depth_clear_hle is answered in your reply (not repeated on 1679477's NVIDIA run); I'm not asking for more there.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@adriadam10 thanks, understood. We need one scene where the bypass fires in the measured window and the gain is outside noise, or we drop the change.

@ntamas94, your Crysis Remastered (CUSA18659) profile looks like the case this is for. If you have time, a pair from the same machine and scene would settle it:

  • main against main with this PR's head (eaafdf9) merged, two runs each, alternating, unprofiled;
  • each run's aps5-summary.jsonl lines and tools/trace_digest.py output;
  • one profiled boot of the change (APS5_PROFILE_DRAW=1), with its [draw-cache] bypassed lines from the same part of the scene.

If that boot shows no bypassed line in the window, you can add fork branch fix/12478-no-hit-window-low (fe3387b) as a third arm, if you like. It also counts a window with no real reuse as low. It isn't on this PR, and it hasn't been measured in a game.

@bcortezf, the same would answer it for the Red Dead Redemption case from #5404, if you still have it set up.

If no scene shows it by Tuesday, 2026-11-03, I'll close this PR.

@TechLevelZero

TechLevelZero commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head eaafdf9 merged onto main 828ac0b · tested 2026-10-31 13:26 UTC · 23 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,418 passed · 5 failed (0 new, 2 also fail on main, 3 unstable on main) · 42 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,465 of 3,048 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (915 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_graphics_maps_fallback 47.7 s, ⚠️ agc_driver_graphics 33.7 s, ⚠️ agc_driver_bda_device 31.4 s
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_submit_progress: failed in 6 of the last 10 main runs
agc_submit_progress: failed in 6 of the last 10 main runs
agc_submit_progress_no_timeline: failed in 8 of the last 10 main runs
Failing on main too (2, not counted against this PR)
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (4, not in the main baseline's validation pass)
agc_driver_draw_cache_cold_scene
agc_driver_draw_cache_cold_scene_off
agc_driver_draw_cache_low_hit_bypass
agc_driver_draw_cache_low_hit_bypass_off
Validation IDs already present on main (4 IDs in 425 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (425 tests): agc_compute_pipeline_replay, agc_driver, agc_driver_address_passes, agc_driver_address_passes_draw_transitions, agc_driver_address_passes_targets_split, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, and 417 more
VUID-vkCmdCopyImage-srcImage-01548 (13 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_plane_sampling, and 5 more
VUID-vkCmdCopyImage-srcImage-01551 (13 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_plane_sampling, and 5 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_srgb8_color_target
Skipped (42)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_msaa_dcc_compared_import_2: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_4: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_8: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_stencil_ref_export: skipped, the device lacks VK_EXT_shader_stencil_export
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_fresh: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or plat
Reproduce
git fetch origin eaafdf934b98cbe710dd6f9bd895f8229650408c 828ac0b2ae74aac181ba128fb59b08a1534f2041
git checkout 828ac0b2ae74aac181ba128fb59b08a1534f2041 && git merge --no-ff eaafdf934b98cbe710dd6f9bd895f8229650408c
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

The conflict in core/libs/prx/libSceAgcDriver/CMakeLists.txt from boykopovar#12862's split is resolved with tools/agc_test_split.py resolve, which moves this PR's test registrations into tests/cmake/.
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 31, 2026

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The head only merges main into eaafdf9; the range-diff of the 8 commits is empty, so the previous review stands. One point still blocks this:

  • No benefit shown. The bypass starts in none of the 57 measured blocks in Resident Evil Village and none in Planet of Lana, so the +13.3% pair isn't attributable to this change. It adds a window, an env var and counters on the draw path, so it needs one scene where the bypass fires under the "seen before counts as useful" rule and the gain is outside noise. Please post a main / change pair from the same machine and scene with the aps5-summary.jsonl lines and tools/trace_digest.py output, plus the [draw-cache] bypassed lines showing it fired in the measured window. Crysis Remastered or the Red Dead Redemption case from #5404 are candidates. If no scene fires and helps, the direction is to drop the change.

@TechLevelZero

TechLevelZero commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head da441e0 merged onto main e6f5730 · tested 2026-11-01 15:59 UTC · 27 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,487 passed · 4 failed (0 new, 3 also fail on main, 1 unstable on main) · 45 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,536 of 3,148 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (935 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.3 s, ⚠️ agc_driver_graphics 32.2 s, ⚠️ agc_driver_graphics_maps_fallback 32.0 s
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 1 of the last 10 main runs
Failing on main too (3, not counted against this PR)
agc_driver_image_table
guest_mmap_executable
guest_socket_options_multicast
Validation IDs already present on main (5 IDs in 484 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (484 tests): agc_driver, agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, and 476 more
VUID-vkCmdCopyImage-srcImage-01548 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-vkCmdCopyImage-srcImage-01551 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_prepared_exports
VUID-VkShaderModuleCreateInfo-pCode-08737 (1 test): agc_driver_image_sample_derivatives
Skipped (45)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_backtoback: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_dcc: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_deferred: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_fps_limit: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_o
Reproduce
git fetch origin da441e01cc5dbc850799b21b26275b504762aec2 e6f57307fa7f47165d7fc1bee945abdb2f6816e7
git checkout e6f57307fa7f47165d7fc1bee945abdb2f6816e7 && git merge --no-ff da441e01cc5dbc850799b21b26275b504762aec2
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@RNK123

RNK123 commented Nov 4, 2026

Copy link
Copy Markdown

RADV/RX 9060 XT: the draw-cache reuse, low-hit bypass and cold-scene tests pass on this head, including bypass-enabled and bypass-off cases.

Head da441e01cc merged onto main c2eafe4461. Seven existing agc_driver_draw_cache_reuse* entries passed 7/7 per run on main and on the merged tree; the merge's four additional agc_driver_draw_cache_low_hit_bypass* and agc_driver_draw_cache_cold_scene* entries also passed, 11/11 per run in total, three serial runs per tree. No test was reported skipped. Khronos validation and the Radeon were confirmed in each run, with no VUID- or SYNC-HAZARD- diagnostics. Both arms had the same unrelated pre-existing LSFG implicit-layer loading failure; the requested Khronos layer did load.

Sensitivity check: on the merged tree, forcing DrawCacheBypass::Skip() to return false made agc_driver_draw_cache_low_hit_bypass fail 3/3 at the expected assertion that low-hit draws were still looked up or inserted. Restoring it passed 3/3. This is a deliberate merged-tree mutation; the new test is not registered on unmodified main.

Host: CachyOS Linux 7.3.1-1-cachyos, GCC 16.2.1, Release, RX 9060 XT (RADV GFX1200), Mesa 26.2.5-arch3.1, Vulkan 1.4.354, Khronos validation 1.4.363.

Reproduction

Build agc_driver_draw_cache_reuse_tests on main and on the PR merged onto it. Set:

export ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1
export VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation VK_LOADER_DEBUG=layer
export VK_LAYER_PATH="$HOME/.local/share/anyps5-tester/vk-layers/usr/share/vulkan/explicit_layer.d"
ctest --test-dir build-main -V -R '^agc_driver_draw_cache_reuse'

Run three times per tree. On the merged tree include the new cases with ctest --test-dir build-main -V -R '^agc_driver_draw_cache_(reuse|cold_scene|low_hit_bypass)'.

Limits: synthetic focused tests, not a game, full suite or performance measurement; no PS5 hardware. The mutation checks activation of bypass, not every warm-up or concurrent-window behavior. AI-assisted independent hardware test run (GPT-6.1 Terra).

@JJenkx

JJenkx commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

A real-title data point for the low-hit-rate case this PR targets: Goat Simulator 3 (PPSA04158) in the open world on Windows (Radeon RX 6700 XT), with libraries from plain main d23df92b38 (not this PR) and APS5_PROFILE_DRAW=1, over a 600 s run.

Run Draw-cache lookups per 10 s No entry Hits Inserts per 10 s
default APS5_DRAW_CACHE_ENTRIES (4096) 184,337 182,435 1,900 (~1.0%) 73
APS5_DRAW_CACHE_ENTRIES=65536 171,394 - 175,149 169,637 - 173,354 1,753 - 1,792 (~1.0%) 79 - 136
  • Raising the entry count changes nothing: the second-sighting admission rarely fires, so this title's draw keys are almost all new each frame (not evicted keys coming back). The hit rate stays at about 1%, well under this PR's 5% threshold.
  • The cost the cache is trying to save: the per-packet key/lookup/validate row is 2.7 - 2.8 us. The capture (8.3 - 8.8 us) and materialize (7.5 - 7.7 us) rows that a hit would skip are paid on nearly every draw anyway.

I did not run this PR's branch, so this is evidence for the premise, not a measurement of the change.

AI-assisted: yes.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@JJenkx thank you for the Goat Simulator 3 (PPSA04158) numbers. They show the case this PR was built for: about 1% of lookups hit, under its 5% threshold, and the larger table doesn't change that, so the keys are new ones rather than evicted ones coming back. While the bypass is on, a draw computes no register key and does no lookup or insert, so at your rates it could save at most the key/lookup/validate row, about 0.5 s of draw-path time per 10 s of your run (184,337 lookups at 2.7 to 2.8 us).

The bar for keeping it, from adriadam10's review, is a measured gain outside noise in a scene where the bypass fires, and 2026-11-03, the date I gave above, has passed without such a pair. So I'm closing this PR. The branch stays on the fork. If a main / change pair on this scene or another shows the gain, it can come back as a new PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* build docs perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants