Skip to content

perf(shader): check f32 NaN sources only for NaN results, narrow window reads - #12548

Closed
josealissonbr wants to merge 5 commits into
boykopovar:mainfrom
josealissonbr:perf/recompiler-rare-nan-propagation
Closed

josealissonbr wants to merge 5 commits into
boykopovar:mainfrom
josealissonbr:perf/recompiler-rare-nan-propagation

Conversation

@josealissonbr

@josealissonbr josealissonbr commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

What

The f32 add, sub, mul and fma NaN rule (nanResultF32) selected over every source after every operation: one compare and one select per source on each of these instructions. The new IR opcode NanPropagateF32 keeps the same result bits but checks the sources in a branch taken only when the host result is NaN. That is exact because every module declares f32 SignedZeroInfNanPreserve, so a NaN source always gives a NaN host result, and the tiny-product flush needs finite factors and a zero addend. Immediate sources are emitted as integer constants, since a float constant bitcast quiets a signaling NaN on NVIDIA. The SRT evaluator evaluates the opcode with the same rule, and the passes that inspect selects (masked select, redundant value, tessellation lowering, denormal flush) know it.

VectorWindowIndexNarrower lists the few values a relative read index can take (adds, shifts, masks, bit-field extracts and selects of known values, at most 16) and, when every relative access of a window is such a read and every listed value is inside the window, reads the listed constant slots and selects between them, so the window needs no indexed access. It changes nothing when any window access is a store or has an index it cannot bound.

Each change alone made no difference in the measured scene; together they shorten the two particle passes of the PPSA01325 title screen. The behaviour is generic: no title, shader or address is matched. docs/dev/debt/shader.md records both, including that the SRT tape compiler does not know the new opcode and falls back to the interpreter.

Tests: ShaderMemory covers the evaluator with NaN, signaling NaN, IEEE and non-IEEE sources and the invalid product; VectorWindow covers the narrowed shape of a dynamic function access; the new GPU test execution/RelativeIndexingBoundedValues runs relative reads whose index takes a small set of values and checks every lane.

Tested

Windows 11 Pro 26200, Intel Core i5-14400, NVIDIA GeForce RTX 5070 (driver 616.64), MinGW GCC 15.2 Release build.

  • Full CTest suite with ANYPS5_REQUIRE_VULKAN=1 and ANYPS5_NO_SHADER_CACHE=1: 2862 of 2862 passed on this head (4dee5b5, main 319621b merged), and 2857 of 2857 on 0c620ad (main e4da19a merged). The 65 main commits between them change one file of the recompiler (ControlFlow/src/GraphBuilder.cpp) and add one AGC test; neither touches the code of this change.
  • Validation: the agc_ tests with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation (Khronos layer built from b2b44c0, API 1.4.366), ANYPS5_REQUIRE_VULKAN=1 and ANYPS5_NO_SHADER_CACHE=1, ctest -R "^agc_" -V, on main e4da19a and on 0c620ad, same machine and GPU: 1138 of 1138 and 1139 of 1139 passed (the extra one is the new test). Neither log reports was not found but was requested by env var VK_INSTANCE_LAYERS; the same 20 tests log validation messages on both, with the same IDs, and this change adds no new VUID- ID.
  • PPSA01325 01.905.000 (Astro's Playroom), relinked with --windows --windows-gui --to-intel, from start without input to the title screen, 3840x2160. main e4da19a against 0c620ad (this branch before the merge of main 319621b), both built in the same session on the same machine. Each capture is 20 s from 110 s after start (APS5_TRACE_SECONDS=110:20, no other switch, log not redirected), after one warm-up run of each build; captures ran alternating main 1, change 1, main 2, change 2. All four windows are on the looping title screen animation.
capture commit presents in 20 s frame p50 / p90 / p99 / max (ms) GPU busy per present
main 1 e4da19a 283 70.5 / 73.8 / 77.1 / 81.7 56.2 ms
change 1 0c620ad 351 56.7 / 59.7 / 64.3 / 66.5 41.5 ms
main 2 e4da19a 284 70.1 / 72.8 / 76.1 / 88.6 55.5 ms
change 2 0c620ad 312 58.0 / 62.0 / 70.3 / 1754.4 42.4 ms

Summary lines:

{"commit":"e4da19aff06e","dirty":false,"env":{"APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"110:20"},"gpu":"NVIDIA GeForce RTX 5070","driver":"NVIDIA 616.64","os":"Windows 10.0.26200","cpu":"Intel(R) Core(TM) i5-14400","cpu_threads":16,"memory_mib":32452,"title_id":"PPSA01325","title":"ASTRO's PLAYROOM","content_version":"01.905.000","resolution":"3840x2160","window":{"spec":"seconds 110:20","first_present":2171,"ms":20022.129},"presents":283,"frame_ms":{"p50":70.459,"p90":73.799,"p99":77.083,"max":81.656},"gpu_busy_ms_per_present":56.152,"worker_busy_pct":{"queue worker 0x0":99.375,"queue worker 0x3d":99.712,"queue worker 0x52":0.000},"top_phases_ms_per_frame":{"Driver.Packet":140.625,"Driver.Packet.memory_wait":56.227,"Driver.Packet.dispatch":26.511,"Driver.Dispatch":25.967,"Vulkan.Dispatch":23.921,"Vulkan.Dispatch.shader_resources":23.665,"Driver.Packet.draw":19.713,"Driver.Draw":19.604},"trace_dropped":false,"trace":"aps5-trace-e4da19aff06e-40620.json.gz"}
{"commit":"0c620add72d2","dirty":false,"env":{"APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"110:20"},"gpu":"NVIDIA GeForce RTX 5070","driver":"NVIDIA 616.64","os":"Windows 10.0.26200","cpu":"Intel(R) Core(TM) i5-14400","cpu_threads":16,"memory_mib":32452,"title_id":"PPSA01325","title":"ASTRO's PLAYROOM","content_version":"01.905.000","resolution":"3840x2160","window":{"spec":"seconds 110:20","first_present":2036,"ms":20054.828},"presents":351,"frame_ms":{"p50":56.749,"p90":59.722,"p99":64.314,"max":66.495},"gpu_busy_ms_per_present":41.454,"worker_busy_pct":{"queue worker 0x0":99.196,"queue worker 0x3d":99.723,"queue worker 0x52":0.000},"top_phases_ms_per_frame":{"Driver.Packet":113.493,"Driver.Packet.memory_wait":52.147,"Driver.Packet.dispatch":16.624,"Driver.Dispatch":16.070,"Graphics.Draw":15.212,"Vulkan.Dispatch":14.220,"Vulkan.Dispatch.shader_resources":13.968,"Driver.Packet.draw":13.903},"trace_dropped":false,"trace":"aps5-trace-0c620add72d2-22844.json.gz"}
{"commit":"e4da19aff06e","dirty":false,"env":{"APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"110:20"},"gpu":"NVIDIA GeForce RTX 5070","driver":"NVIDIA 616.64","os":"Windows 10.0.26200","cpu":"Intel(R) Core(TM) i5-14400","cpu_threads":16,"memory_mib":32452,"title_id":"PPSA01325","title":"ASTRO's PLAYROOM","content_version":"01.905.000","resolution":"3840x2160","window":{"spec":"seconds 110:20","first_present":2173,"ms":20028.327},"presents":284,"frame_ms":{"p50":70.110,"p90":72.849,"p99":76.116,"max":88.590},"gpu_busy_ms_per_present":55.493,"worker_busy_pct":{"queue worker 0x0":99.379,"queue worker 0x3d":99.696,"queue worker 0x52":0.000},"top_phases_ms_per_frame":{"Driver.Packet":140.232,"Driver.Packet.memory_wait":55.518,"Driver.Packet.dispatch":26.931,"Driver.Dispatch":26.399,"Vulkan.Dispatch":24.206,"Vulkan.Dispatch.shader_resources":23.942,"Driver.Packet.draw":19.938,"Driver.Draw":19.831},"trace_dropped":false,"trace":"aps5-trace-e4da19aff06e-35696.json.gz"}
{"commit":"0c620add72d2","dirty":false,"env":{"APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"110:20"},"gpu":"NVIDIA GeForce RTX 5070","driver":"NVIDIA 616.64","os":"Windows 10.0.26200","cpu":"Intel(R) Core(TM) i5-14400","cpu_threads":16,"memory_mib":32452,"title_id":"PPSA01325","title":"ASTRO's PLAYROOM","content_version":"01.905.000","resolution":"3840x2160","window":{"spec":"seconds 110:20","first_present":2410,"ms":20011.073},"presents":312,"frame_ms":{"p50":58.020,"p90":61.977,"p99":70.254,"max":1754.371},"gpu_busy_ms_per_present":42.432,"worker_busy_pct":{"queue worker 0x0":99.261,"queue worker 0x3d":99.474,"queue worker 0x52":0.000},"top_phases_ms_per_frame":{"Driver.Packet":127.268,"Driver.Packet.memory_wait":52.553,"Graphics.Draw":22.970,"Driver.Packet.draw":21.051,"Driver.Draw":20.935,"Graphics.Draw.draw_and_resource_release":20.802,"Driver.Packet.prepare_memory":18.271,"Driver.Packet.dispatch":17.595},"trace_dropped":false,"trace":"aps5-trace-0c620add72d2-15132.json.gz"}

tools/trace_digest.py on main 1 and change 1: GPU busy drops from 56.1 to 41.4 ms per frame and frame p50 from 70.5 to 56.7 ms (about 14.2 to 17.6 FPS). The queue worker that waits for the GPU (queue worker 0x3d) spends 54.3 ms per frame in Driver.Packet.memory_wait on main and 50.4 ms on this change, and the presenter waits 15.4 against 4.9 ms. The 1754 ms frame in change 2 is one Vulkan.GraphicsPipelineLibrary creation (1643 ms) for a pipeline the title first uses there: with the faster build, 110 s after start falls later in the title animation (present 2494 against 2171 on main), and no other frame of the change captures exceeds 192 ms.

Before this merge, a local GPU pass timer (not part of this change) measured the two particle passes on main e2a5118 at 16.6 and 14.7 ms of GPU time per frame, 17.7 and 16.0 ms with the NaN branch alone, and 8.6-9.0 and 6.2-6.5 ms with both changes.

tools/trace_digest.py, main 1

seconds 110:20 from present 2171: 283 presents, frame p50 70.5 / p90 73.8 / p99 77.1 / max 81.7 ms, GPU busy 56.2 ms per present
NVIDIA GeForce RTX 5070, NVIDIA 616.64, Windows 10.0.26200, 3840x2160, commit e4da19a, dropped: no

{"commit":"e4da19aff06e","dirty":false,"env":{"APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"110:20"},"gpu":"NVIDIA GeForce RTX 5070","driver":"NVIDIA 616.64","os":"Windows 10.0.26200","cpu":"Intel(R) Core(TM) i5-14400","cpu_threads":16,"memory_mib":32452,"title_id":"PPSA01325","title":"ASTRO's PLAYROOM","content_version":"01.905.000","resolution":"3840x2160","window":{"spec":"seconds 110:20","first_present":2171,"ms":20022.129},"presents":283,"frame_ms":{"p50":70.459,"p90":73.799,"p99":77.083,"max":81.656},"gpu_busy_ms_per_present":56.152,"worker_busy_pct":{"queue worker 0x0":99.375,"queue worker 0x3d":99.712,"queue worker 0x52":0.0},"top_phases_ms_per_frame":{"Driver.Packet":140.625,"Driver.Packet.memory_wait":56.227,"Driver.Packet.dispatch":26.511,"Driver.Dispatch":25.967,"Vulkan.Dispatch":23.921,"Vulkan.Dispatch.shader_resources":23.665,"Driver.Packet.draw":19.713,"Driver.Draw":19.604},"trace_dropped":false,"trace":"aps5-trace-e4da19aff06e-40620.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 2230: 81.7 ms at 4073 ms: Driver.Packet (queue worker 0x3d) 81.5, Driver.Packet (queue worker 0x0) 76.9, batch (gpu) 64.4, Driver.Packet.memory_wait (queue worker 0x3d) 56.1
  • present 2295: 81.5 ms at 8780 ms: Driver.Packet (queue worker 0x3d) 81.3, Driver.Packet (queue worker 0x0) 76.8, batch (gpu) 58.9, Driver.Packet.memory_wait (queue worker 0x3d) 57.7
  • present 2288: 77.1 ms at 8265 ms: Driver.Packet (queue worker 0x3d) 76.9, Driver.Packet (queue worker 0x0) 72.7, batch (gpu) 61.5, Driver.Packet.memory_wait (queue worker 0x3d) 50.6
  • present 2329: 76.9 ms at 11207 ms: Driver.Packet (queue worker 0x3d) 76.7, Driver.Packet (queue worker 0x0) 71.9, batch (gpu) 59.5, Driver.Packet.memory_wait (queue worker 0x3d) 53.1
  • present 2269: 76.9 ms at 6886 ms: Driver.Packet (queue worker 0x3d) 76.7, Driver.Packet (queue worker 0x0) 72.5, batch (gpu) 59.3, Driver.Packet.memory_wait (queue worker 0x3d) 51.3

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 48.4 (68 %) 18.1 (26 %) 4.2 15.5 Driver.Packet 66.3, Driver.EndSubmission 0.1
title 0.1 (0 %) 0.0 (0 %) 70.7 0.1 Shader.ResolveGraphicsStagesAbi 0.1, Shader.ResolveGraphicsAbi 0.0
title 0.1 (0 %) 0.0 (0 %) 70.7 0.1 Shader.ResolveGraphicsStagesAbi 0.1, Shader.ResolveGraphicsAbi 0.0
title 0.1 (0 %) 0.0 (0 %) 70.7 0.3 Shader.ResolveGraphicsStagesAbi 0.0, Shader.ResolveGraphicsAbi 0.0
draw committer 21.0 (30 %) 13.5 (19 %) 36.3 4.8 Graphics.Draw 13.2, Vulkan.DrawFromRecipe 6.4
queue worker 0x3d 16.1 (23 %) 54.3 (77 %) 0.4 0.6 Driver.Packet 70.4, Recorder.Submit 0.0
presenter 0.9 (1 %) 15.4 (22 %) 54.5 0.1 VideoOut.Flip 16.2, Driver.Present 0.0
title 0.0 (0 %) 0.0 (0 %) 70.7 0.0 Shader.ResolveGraphicsStagesAbi 0.0
gpu 56.1 (79 %) 0.0 (0 %) 14.6 0.0 batch 56.1

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 136.7, Driver.Packet.memory_wait 56.2, batch 56.1, Driver.Packet.dispatch 26.5, Driver.Dispatch 25.9, Vulkan.Dispatch 23.9, Vulkan.Dispatch.shader_resources 23.6, Driver.Packet.draw 18.2, Driver.Draw 18.1, Driver.Packet.prepare_memory 17.9

Longest waits

  • Driver.Packet.memory_wait (queue worker 0x3d) 59.3 ms at 4105 ms, present 2230
  • Driver.Packet.memory_wait (queue worker 0x3d) 57.1 ms at 8810 ms, present 2295
  • Driver.Packet.memory_wait (queue worker 0x3d) 56.5 ms at 8004 ms, present 2284
  • Driver.Packet.memory_wait (queue worker 0x3d) 54.7 ms at 11237 ms, present 2329
  • Driver.Packet.memory_wait (queue worker 0x3d) 54.7 ms at 7068 ms, present 2271
  • Driver.Packet.memory_wait (queue worker 0x3d) 54.0 ms at 8298 ms, present 2288
  • Driver.Packet.memory_wait (queue worker 0x3d) 53.0 ms at 6769 ms, present 2267
  • Driver.Packet.memory_wait (queue worker 0x3d) 52.8 ms at 12121 ms, present 2341
  • Driver.Packet.memory_wait (queue worker 0x3d) 52.8 ms at 4181 ms, present 2231
  • Driver.Packet.memory_wait (queue worker 0x3d) 52.8 ms at 9453 ms, present 2304

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

  • batch 12290: 17.4 ms at 15028 ms, present 2382: GPU no ranges; recorded by Graphics.Draw (draw committer) 0.4, Graphics.Draw.draw_and_resource_release (draw committer) 0.4, Recorder.Submit (draw committer) 0.0
  • batch 3409: 17.0 ms at 4070 ms, present 2229: GPU no ranges; recorded by Graphics.Draw (draw committer) 0.9, Graphics.Draw.draw_and_resource_release (draw committer) 0.9, Recorder.Submit (draw committer) 0.0, Graphics.Draw.validate (draw committer) 0.0
  • batch 14557: 16.8 ms at 17771 ms, present 2421: GPU no ranges; recorded by Graphics.Draw (draw committer) 0.4, Graphics.Draw.draw_and_resource_release (draw committer) 0.4, Recorder.Submit (draw committer) 0.0
  • batch 14791: 16.6 ms at 18052 ms, present 2425: GPU no ranges; recorded by Graphics.Draw (draw committer) 0.8, Graphics.Draw.draw_and_resource_release (draw committer) 0.7, Recorder.Submit (draw committer) 0.0
  • batch 9270: 16.6 ms at 11356 ms, present 2330: GPU no ranges; recorded by Graphics.Draw (draw committer) 0.9, Graphics.Draw.draw_and_resource_release (draw committer) 0.8, Recorder.Submit (draw committer) 0.0, Graphics.Draw.validate (draw committer) 0.0
tools/trace_digest.py, change 1

seconds 110:20 from present 2036: 351 presents, frame p50 56.7 / p90 59.7 / p99 64.3 / max 66.5 ms, GPU busy 41.5 ms per present
NVIDIA GeForce RTX 5070, NVIDIA 616.64, Windows 10.0.26200, 3840x2160, commit 0c620ad, dropped: no

{"commit":"0c620add72d2","dirty":false,"env":{"APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"110:20"},"gpu":"NVIDIA GeForce RTX 5070","driver":"NVIDIA 616.64","os":"Windows 10.0.26200","cpu":"Intel(R) Core(TM) i5-14400","cpu_threads":16,"memory_mib":32452,"title_id":"PPSA01325","title":"ASTRO's PLAYROOM","content_version":"01.905.000","resolution":"3840x2160","window":{"spec":"seconds 110:20","first_present":2036,"ms":20054.828},"presents":351,"frame_ms":{"p50":56.749,"p90":59.722,"p99":64.314,"max":66.495},"gpu_busy_ms_per_present":41.454,"worker_busy_pct":{"queue worker 0x0":99.196,"queue worker 0x3d":99.723,"queue worker 0x52":0.0},"top_phases_ms_per_frame":{"Driver.Packet":113.493,"Driver.Packet.memory_wait":52.147,"Driver.Packet.dispatch":16.624,"Driver.Dispatch":16.07,"Graphics.Draw":15.212,"Vulkan.Dispatch":14.22,"Vulkan.Dispatch.shader_resources":13.968,"Driver.Packet.draw":13.903},"trace_dropped":false,"trace":"aps5-trace-0c620add72d2-22844.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 2036: 66.5 ms at 0 ms: Driver.Packet (queue worker 0x0) 61.8, Driver.Packet (queue worker 0x3d) 55.7, Driver.Packet.memory_wait (queue worker 0x3d) 43.8, batch (gpu) 42.0
  • present 2068: 65.5 ms at 1852 ms: Driver.Packet (queue worker 0x3d) 65.2, Driver.Packet (queue worker 0x0) 60.7, Driver.Packet.memory_wait (queue worker 0x3d) 51.1, batch (gpu) 40.6
  • present 2125: 64.6 ms at 5086 ms: Driver.Packet (queue worker 0x3d) 64.4, Driver.Packet (queue worker 0x0) 60.7, Driver.Packet.memory_wait (queue worker 0x3d) 51.2, batch (gpu) 40.5
  • present 2037: 64.3 ms at 66 ms: Driver.Packet (queue worker 0x3d) 64.1, Driver.Packet (queue worker 0x0) 59.2, Driver.Packet.memory_wait (queue worker 0x3d) 51.0, batch (gpu) 39.6
  • present 2158: 63.8 ms at 6985 ms: Driver.Packet (queue worker 0x3d) 63.7, Driver.Packet (queue worker 0x0) 59.0, Driver.Packet.memory_wait (queue worker 0x3d) 50.9, batch (gpu) 43.3

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 40.1 (70 %) 12.9 (23 %) 4.2 15.6 Driver.Packet 52.8, Driver.EndSubmission 0.1
title 0.1 (0 %) 0.0 (0 %) 57.1 0.1 Shader.ResolveGraphicsStagesAbi 0.1, Shader.ResolveGraphicsAbi 0.0
title 0.1 (0 %) 0.0 (0 %) 57.0 0.1 Shader.ResolveGraphicsStagesAbi 0.1, Shader.ResolveGraphicsAbi 0.0
title 0.1 (0 %) 0.0 (0 %) 57.1 0.3 Shader.ResolveGraphicsStagesAbi 0.0, Shader.ResolveGraphicsAbi 0.0
draw committer 22.0 (38 %) 4.0 (7 %) 31.2 4.8 Graphics.Draw 13.5, Vulkan.DrawFromRecipe 6.8
queue worker 0x3d 6.4 (11 %) 50.4 (88 %) 0.3 0.6 Driver.Packet 56.8, Driver.EndSubmission 0.0
presenter 0.9 (1 %) 4.9 (9 %) 51.4 0.1 VideoOut.Flip 5.8, Driver.Present 0.0
title 0.0 (0 %) 0.0 (0 %) 57.1 0.0 Shader.ResolveGraphicsStagesAbi 0.0
gpu 41.4 (73 %) 0.0 (0 %) 15.7 0.0 batch 41.4

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 109.6, Driver.Packet.memory_wait 52.1, batch 41.4, Driver.Packet.dispatch 16.6, Driver.Dispatch 16.0, Vulkan.Dispatch 14.2, Vulkan.Dispatch.shader_resources 13.9, Graphics.Draw 13.8, Driver.Packet.prepare_memory 12.9, Driver.Packet.draw 12.4

Longest waits

  • Driver.Packet.memory_wait (queue worker 0x3d) 56.1 ms at 23 ms, present 2036
  • Driver.Packet.memory_wait (queue worker 0x3d) 54.9 ms at 17766 ms, present 2347
  • Driver.Packet.memory_wait (queue worker 0x3d) 52.6 ms at 9412 ms, present 2200
  • Driver.Packet.memory_wait (queue worker 0x3d) 51.4 ms at 1812 ms, present 2067
  • Driver.Packet.memory_wait (queue worker 0x3d) 51.3 ms at 7007 ms, present 2158
  • Driver.Packet.memory_wait (queue worker 0x3d) 50.0 ms at 5050 ms, present 2124
  • Driver.Packet.memory_wait (queue worker 0x3d) 48.5 ms at 5335 ms, present 2129
  • Driver.Packet.memory_wait (queue worker 0x3d) 48.1 ms at 554 ms, present 2045
  • Driver.Packet.memory_wait (queue worker 0x3d) 48.1 ms at 12094 ms, present 2247
  • Driver.Packet.memory_wait (queue worker 0x3d) 48.1 ms at 9180 ms, present 2196

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

  • batch 4315: 10.5 ms at 4246 ms, present 2110: GPU no ranges; recorded by Driver.Packet (queue worker 0x3d) 12.1, Driver.Packet.prepare_memory (queue worker 0x3d) 10.7, Recorder.WaitSerial (queue worker 0x3d) 10.6, Driver.Packet.dispatch (queue worker 0x3d) 1.4
  • batch 10631: 10.0 ms at 10530 ms, present 2219: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 28.2, Driver.Packet.dispatch (queue worker 0x0) 11.5, Driver.Dispatch (queue worker 0x0) 11.5, Vulkan.Dispatch (queue worker 0x0) 10.8
  • batch 10676: 10.0 ms at 10565 ms, present 2220: GPU no ranges; recorded by Driver.Packet (queue worker 0x3d) 12.7, Driver.Packet.prepare_memory (queue worker 0x3d) 10.2, Recorder.WaitSerial (queue worker 0x3d) 10.1, Driver.Packet.dispatch (queue worker 0x3d) 2.5
  • batch 1890: 9.9 ms at 1892 ms, present 2068: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 29.1, Driver.Packet.dispatch (queue worker 0x0) 12.6, Driver.Dispatch (queue worker 0x0) 12.6, Vulkan.Dispatch (queue worker 0x0) 12.0
  • batch 10574: 9.9 ms at 10471 ms, present 2218: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 27.8, Driver.Packet.dispatch (queue worker 0x0) 11.1, Driver.Dispatch (queue worker 0x0) 11.1, Vulkan.Dispatch (queue worker 0x0) 10.5

Traces (slice timings only; they open in ui.perfetto.dev):

aps5-trace-0c620add72d2-22844.json.gz
aps5-trace-e4da19aff06e-35696.json.gz
aps5-trace-e4da19aff06e-40620.json.gz
aps5-trace-0c620add72d2-15132.json.gz

Overlap: this is offered in place of #4287, which reduces the same nanResultF32 select chain to one quiet and one fallback select and has been waiting for title numbers; this change keeps the NaN rule out of the common path instead and brings those numbers. #10720 changes the same lines behind APS5_FAST_F32; #12233 touches the neighbouring line of docs/dev/debt/shader.md and #12324 a line of Recompiler.cpp next to the new pass.

Checklist

  • Based on current main; no other open PR implements the same functions
  • 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
  • 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
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 5070, driver 616.64, Windows 11 Pro 26200
  • AI-assisted: yes

🤖 Generated with Claude Code

josealissonbr and others added 2 commits October 27, 2026 11:45
…ow reads

The f32 add, sub, mul and fma NaN rule selected over every source after
every operation. NanPropagateF32 keeps the same bits but checks the
sources in a branch taken only when the host result is NaN, which every
NaN source produces under SignedZeroInfNanPreserve. The SRT evaluator
evaluates the opcode with the same rule.

VectorWindowIndexNarrower lists the few values a relative read index can
take and, when every relative access of a window is such a read, reads
constant slots instead, so the window takes no indexed access.

Together they take the two particle passes of the PPSA01325 title screen
from 16.6 and 14.7 ms to about 8.8 and 6.3 ms of GPU time per frame on an
RTX 5070; either change alone made no gain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the perf Performance change label Oct 28, 2026
@adriadam10 adriadam10 self-assigned this Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

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 4287 core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp
PR 5021 core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
docs/dev/debt/shader.md
PR 5371 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 5609 core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp
core/shader/recompiler/Recompiler.cpp
PR 5925 core/shader/recompiler/CMakeLists.txt
PR 6235 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 6280 docs/dev/debt/shader.md
PR 6290 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 6412 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 6416 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 6488 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 6751 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 6858 core/shader/recompiler/Recompiler.cpp
PR 6924 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 6970 core/shader/recompiler/Recompiler.cpp
PR 7085 docs/dev/debt/shader.md
PR 7392 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
docs/dev/debt/shader.md
PR 7395 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 7410 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrOpcode.hpp
core/shader/recompiler/IntermediateRepresentation/src/IrOpcode.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterInstructions.hpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp
docs/dev/debt/shader.md
PR 7522 core/shader/recompiler/Recompiler.cpp
PR 7622 core/shader/recompiler/CMakeLists.txt
PR 7642 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 7684 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 8004 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 8458 docs/dev/debt/shader.md
PR 8939 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9020 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9335 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9356 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
PR 9387 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9457 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9508 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 9633 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9748 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9749 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9790 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 9889 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 9897 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 9969 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 10193 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 10233 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 10249 core/shader/recompiler/Optimization/src/TessellationLowering.cpp
PR 10351 core/shader/recompiler/Recompiler.cpp
PR 10359 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 10489 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 10652 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 10757 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 10867 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Optimization/src/MaskedSelectEliminator.cpp
docs/dev/debt/shader.md
PR 11351 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 11483 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 11490 core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp
PR 11551 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 12002 core/shader/recompiler/IntermediateRepresentation/src/IrOpcode.cpp
PR 12316 docs/dev/debt/shader.md
PR 12324 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Optimization/src/RedundantValueEliminator.cpp
core/shader/recompiler/Recompiler.cpp
PR 12458 docs/dev/debt/shader.md
PR 12790 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 12828 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
PR 12840 core/shader/recompiler/Recompiler.cpp
PR 12944 core/shader/recompiler/IntermediateRepresentation/src/IrOpcode.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 13486 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 13847 docs/dev/debt/shader.md
PR 13928 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 13929 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 14032 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 14068 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 14072 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 14081 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 14085 docs/dev/debt/shader.md
PR 14212 docs/dev/debt/shader.md
PR 14217 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 14218 core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterInstructions.hpp
core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
docs/dev/debt/shader.md
PR 14247 docs/dev/debt/shader.md
PR 14265 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 14341 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 14367 core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
PR 14377 docs/dev/debt/shader.md
PR 14561 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 14628 docs/dev/debt/shader.md
PR 14633 docs/dev/debt/shader.md
PR 14636 core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 14692 docs/dev/debt/shader.md
PR 14708 core/shader/recompiler/SpirvBackend/src/SpirvFlowEmitter.cpp
PR 14793 docs/dev/debt/shader.md
PR 14795 docs/dev/debt/shader.md
PR 14821 core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp
docs/dev/debt/shader.md
PR 14830 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Optimization/src/SrtWalker/SrtInstructionPredicates.cpp
PR 14853 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 14871 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 14900 docs/dev/debt/shader.md
PR 14904 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 14913 docs/dev/debt/shader.md
PR 14944 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
PR 14971 core/shader/recompiler/CMakeLists.txt
PR 15243 core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp
docs/dev/debt/shader.md
PR 15256 docs/dev/debt/shader.md
PR 15304 docs/dev/debt/shader.md
PR 15305 docs/dev/debt/shader.md
PR 15334 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 15338 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 15416 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 15450 docs/dev/debt/shader.md
PR 15458 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 15462 core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp
docs/dev/debt/shader.md
PR 15488 core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp
docs/dev/debt/shader.md
PR 15497 docs/dev/debt/shader.md
PR 15512 core/shader/recompiler/CMakeLists.txt
docs/dev/debt/shader.md
PR 15520 core/libs/prx/libSceAgcDriver/tests/VectorWindow.cpp
docs/dev/debt/shader.md
PR 15542 core/shader/recompiler/CMakeLists.txt
docs/dev/debt/shader.md
PR 15548 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
PR 15555 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 15573 core/shader/recompiler/CMakeLists.txt
docs/dev/debt/shader.md
PR 15576 docs/dev/debt/shader.md
PR 15608 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 15611 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 15648 docs/dev/debt/shader.md
PR 15655 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 15668 docs/dev/debt/shader.md
PR 15680 core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Optimization/src/TessellationLowering.cpp
docs/dev/debt/shader.md
PR 15681 docs/dev/debt/shader.md
PR 15705 core/shader/recompiler/CMakeLists.txt
core/shader/recompiler/Recompiler.cpp
PR 15719 core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 15728 core/shader/recompiler/CMakeLists.txt
docs/dev/debt/shader.md
PR 15741 core/shader/recompiler/CMakeLists.txt
PR 15769 docs/dev/debt/shader.md

@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.

Reviewed — changes requested

The performance evidence is present, but this branch overlaps open PRs #4287 and #10720 without recording an agreed integration order; combining it with #10720 produces a source conflict.

What I ran

  • Reviewed exact head 4dee5b5e3296c643731e19eca13ddad80d1e49ab against base 319621ba2e578bd053b0baba2877fe70520e0737; current-main merge tree db3ff82497c56456347fdd03f9822d02a37bb553 is clean.
  • Ran git diff --check refs/review/current-main...refs/review/12548 — pass, no output.
  • Compared both declared related PRs: #4287 is open and changes the same nanResultF32 behavior; #10720 is open and changes the same operand-access logic. Pairwise merge with #4287 is clean, but pairwise merge with #10720 reports a content conflict in OperandAccess.cpp.
  • Inspected the new NaN-propagation emitter/evaluator and finite-set vector-window narrowing logic. No separate correctness defect was established in that source inspection.
  • Refreshed hosted checks: Windows, Ubuntu/Windows relinker, relinker ASan, conventions, eligibility, labels and report pass; Linux product and specialized jobs are skipped; macOS relinker checks are pending.

Results

Check Result
Current-main merge preview Clean
Diff check Pass
Merge preview with #4287 Clean tree; same NaN-result logic is being proposed
Merge preview with #10720 Content conflict in OperandAccess.cpp
Performance report requirements Body includes paired same-scene summaries, four attached traces and trace_digest.py output; captures report no dropped events
Hosted Windows and Ubuntu/Windows relinker, ASan, policy Pass
Hosted Linux product Skipped
Hosted macOS relinker Pending
Focused Vulkan/performance runs Reported by author; not independently run
Raw combined-merge output with #10720
CONFLICT (content): Merge conflict in core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp

Negative control

Assertion Change under test Result
The NaN and vector-window changes preserve behavior and improve the reported title workload Author reports current-main versus change runs, full Vulkan CTest, and validation-layer comparison Evidence and raw summaries are included in the PR body; I did not run the GPU control locally

Findings

Blocking

  • Coordinate and declare the overlapping work. #4287 remains open and changes the same nanResultF32 NaN selection behavior; the PR says this is offered in its place, but no agreement or supersession order is recorded. #10720 also remains open, and a combined merge preview with its current head conflicts in OperandAccess.cpp. The repository requires authors of overlapping PRs to agree on landing order and record it with Depends on. Please coordinate with the affected authors and update the checklist/body to state the agreed order or replacement plan; rebase and rerun overlap checks where required. This request is about integration, not pressure to close either PR.

Non-blocking

The performance report is substantially complete: paired captures use the same title, scene, machine, driver and resolution; the four trace files and digest output are attached. I did not independently validate those trace binaries or reproduce the Vulkan measurements.

Sources

Not verified

I did not run the full CTest suite, Vulkan validation tests, GPU capture, the SRT tape path, or console/title tests. Hosted product Linux is skipped and macOS relinker checks were still pending. Author-reported test runs and trace measurements are not my own runs.

To get this to a good state

Record an author-agreed integration order/replacement plan for #4287 and #10720, then rebase and rerun the overlap check. I will review the updated head and retest the affected integration paths.

@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.

Checked the diff against the existing nanResultF32 rule. The NaN branch keeps the same bits (the legacy mul/mad forms zero the factors before the call, the invalid-product guard for a NaN addend is kept, the SRT evaluator applies the same order), and the window narrower falls back whenever any access is a store or an index is unbounded. The numbers are clear. Two things block the merge:

  • Overlap, no order. OperandAccess.cpp:345-351 rewrites the same nanResultF32 body that #4287 reduces (waiting for title numbers, with @oneandonlydean's ordering "#4287 first, then #10720 rebases onto it"), and #10720 changes the same lines behind APS5_FAST_F32. Please say which of the three lands and how: either list #4287/#10720 in Depends on and rebase on the one that goes first, or state that this replaces #4287 and why the branch version is better, and show that it still merges with #10720 (it conflicts today, as MarcZX10 reported).
  • Unrelated behaviour change. SrtEvaluator.cpp:372 turns if (value.ArgumentCount() < *arguments) return true; into return false; for every opcode in evaluatedArguments, not only NanPropagateF32. Drop it, or explain why it is needed and add a test where it changes the result.

Smaller: docs/dev/debt/shader.md is accurate, but the 16-value limit of the narrower and the compare-chain cost are unmeasured; a line in Tested on a program with many listed reads would settle that.

…NanPropagateF32

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 4dee5b5 merged onto main f6fddd6 · tested 2026-10-30 05:21 UTC · 25 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,276 passed · 4 failed (0 new, 2 also fail on main, 2 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,321 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 (870 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_bda_device 66.6 s
Intermittent validation messages (1, seen once in the parallel run, not reproduced when the test was re-run alone 2 times; not counted against this PR)
agc_driver_depth_clear_hle: VUID-vkCmdCopyBuffer-commonparent (6x)
Unstable on main (2, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_depth_clear_hle: failed in 1 of the last 7 main runs
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 (1, not in the main baseline's validation pass)
agc_driver_relative_indexing_bounded_values
Validation IDs already present on main (4 IDs in 394 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (394 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 386 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 4dee5b5e3296c643731e19eca13ddad80d1e49ab f6fddd60d826831f70f7c62e25423610ee742bcc
git checkout f6fddd60d826831f70f7c62e25423610ee742bcc && git merge --no-ff 4dee5b5e3296c643731e19eca13ddad80d1e49ab
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.

@bunbeans2-arch

Copy link
Copy Markdown
Contributor

An AMD RDNA 4 run on Windows of 4dee5b5e32 as is. Its only conflict with current main is docs/dev/debt/shader.md, so I built the head itself (base 319621ba2e).

Windows 11 Pro 10.0.22631, AMD Radeon RX 9070 XT (1002:7550, driver 32.0.32015.7029, amdvlk64), MSYS2 UCRT64 g++ 16.1.0, Release. ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation; with VK_LOADER_DEBUG=layer the loader logs Insert instance layer "VK_LAYER_KHRONOS_validation" in every run of every test below that creates a Vulkan instance. 3 runs:

  • The new agc_driver_relative_indexing_bounded_values passes 3 of 3, with no VUID- line.
  • I didn't run ShaderMemory.cpp or VectorWindow.cpp.

AI-assisted: yes (Claude Code)

@thuanquang

Copy link
Copy Markdown
Contributor

@josealissonbr An AMD RDNA 2 run of this head and one note from reading it.

Setup. RX 6700 XT (gfx1031), AMD driver 32.0.21045.16010, Windows 11 26200, Ryzen 5 5600X, WinLibs GCC 15.2.0, Release. Head 4dee5b5e32 merged cleanly onto our base d40655b86e as 947eb841de, which differs from the base by exactly this PR's diff. The base is main bb04a4f1ea with #12074 (merged since) and #7844, which touch only AGC buffer memory and its tests, not the recompiler; Persona 5 Royal needs #7844 to leave its slow host-import state. The base is behind current main, so this is supporting evidence, not a run on current main.

Tests, with ANYPS5_REQUIRE_VULKAN=1 and ANYPS5_NO_SHADER_CACHE=1, once plain and once with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation (layer built from 15c64e7, API 1.4.363; VK_LOADER_DEBUG=layer, ctest -V): the f32 NaN, quieting, FMA, min/max and denormal tests, the vector-window tests and agc_shader_memory pass 13 of 13 on the base and, with agc_driver_relative_indexing_bounded_values, 14 of 14 on this PR. The loader inserts the layer once in each test that creates a Vulkan instance (9 on the base, 10 on the PR; the other four tests create none). Neither log has a "was not found but was requested" line, a VUID- line or a Validation Error.

Persona 5 Royal (PPSA05110, own dump), first gameplay area at 3840x2160. Four legs alternating base and PR, each with a 4 s trace at 560 s; other processes used a median 2.7-3.2 % CPU over each window ±20 s. Summary-line env: APS5_TRACE_SECONDS=560:4, our input driver's APS5_NO_PAD_INPUT and APS5_PAD_INPUT_FILE, frame dumps (APS5_DUMP_FRAMES=1300, APS5_DUMP_FRAMES_EVERY=20) and APS5_TRACE_DIR; no APS5_PROFILE_*. Traces are not attached.

leg build presents in the window (per 10 s) frame p50 / p90, ms GPU ms per present
1 base 67 (166.0) 57.3 / 68.4 39.0
2 PR 66 (162.8) 57.7 / 70.1 39.1
3 base 67 (167.2) 58.1 / 69.0 39.3
4 PR 66 (165.0) 57.0 / 69.5 39.2

GPU time per present didn't change: +0.14, -0.21 and -0.06 ms in the three neighbouring pairs (1-2, 2-3, 3-4). Frame time here is set by the CPU side (the GPU is busy 39 ms of a 57 ms frame, and the queue worker's worker_busy_pct is 97 %), so GPU time is where a shader cost or gain would show. The NaN branch does reach this title's shaders: agc_shader_replay --spv on three of its costliest fragment programs in an earlier GPU profile gives 8-11 % fewer OpSelect with this PR. This scene is draw-heavy (about 730 draws and 9 dispatches per frame), and we did not check whether the window narrower fires in it, so this run doesn't test the particle-pass gain you measured.

On the CPU side the PR legs come out worse in all three pairs: one present fewer per window (66 against 67), 0.5-2.2 ms per frame more queue-worker time and a 0.5-1.7 ms higher p90. Part of that is one 72-75 ms Shader.DrawStage.materialize in each PR window, worth about one frame and 1.1 ms per frame of worker time; the longest shader compile in the base windows is 0.17 ms. That stall is not specific to this change: the base build had one of the same size (75.2 and 72.5 ms) in both of its windows in an earlier pair in this scene, with warm caches. With two legs per side we can't tell whether the rest comes from this change. The PR build's first leg started with an empty shader cache (0 of 829 hits in its first 10 s; the base's was warm), but no window has shader-cache traffic or a pipeline creation.

The emulator dumped a 960x540 frame every 20 presents for our input driver, 3-4 per window at 0.5-0.8 ms each. p99 is left out: with 66-67 frames it is the slowest single frame (base: 246 ms for the window's first frame, and 75 ms; PR: the 148 and 141 ms stall frames).

Note: the RedundantValueEliminator entry for NanPropagateF32 never applies. RedundantValueEliminator.cpp:45 adds the op to the recomputable set, but ValueKey holds 4 operands (:159) and the scan skips any value with more (:292). The op is declared with 6 arguments (IrOpcode.cpp:528) and nanResultF32 always emits 6 (OperandAccess.cpp:351), so identical NanPropagateF32 values are never merged, where main merged the select-chain ops they replace. Performance only: widening the key to 6 operands would let them merge; otherwise the line can go.

AI-assisted: yes (Claude Code)

…/recompiler-rare-nan-propagation

# Conflicts:
#	docs/dev/debt/shader.md
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 31, 2026
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head e3b2b4c merged onto main 73f4f7e · tested 2026-10-31 15:31 UTC · 21 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,354 passed · 5 failed (0 new, 4 also fail on main, 1 unstable on main) · 48 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,407 of 3,072 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 (888 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_bda_device 53.1 s, ⚠️ agc_driver_graphics_maps_fallback 31.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 7 of the last 10 main runs
Failing on main too (4, not counted against this PR)
agc_submit_progress
agc_submit_progress_no_timeline
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (1, not in the main baseline's validation pass)
agc_driver_relative_indexing_bounded_values
Validation IDs already present on main (3 IDs in 392 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (392 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 384 more
VUID-vkCmdCopyImage-srcImage-01548 (12 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 4 more
VUID-vkCmdCopyImage-srcImage-01551 (12 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 4 more
Skipped (48)
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_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_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 plat
Reproduce
git fetch origin e3b2b4c1f6bff3044d2c799fbb8f96a49276472a 73f4f7e06e4f210a8c6570e335fd654dc0a86134
git checkout 73f4f7e06e4f210a8c6570e335fd654dc0a86134 && git merge --no-ff e3b2b4c1f6bff3044d2c799fbb8f96a49276472a
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.

@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.

Checked the new head against our last review. The SrtEvaluator.cpp change is fixed in 965b877: the short-argument path is back to return true and only NanPropagateF32 takes the new case.

One point is still open:

  • Overlap, no order. OperandAccess.cpp (the nanResultF32 rewrite) still conflicts with #4287 and with #10720 (git merge-tree against current heads), and the body says Depends on: none. Please say which of the three lands and how: either list the one that goes first in Depends on and rebase onto it, or state that this replaces #4287 and why, and show that it still merges with #10720.

Smaller, optional: a line in Tested on a program with many listed reads would settle the 16-value limit of the narrower and its compare-chain cost.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Nov 1, 2026
@JJenkx

JJenkx commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Independent AMD Linux correctness evidence for head e3b2b4c1f6bff3044d2c799fbb8f96a49276472a, plus a current-main integration note. No native title speedup has been measured here yet.

Hardware: Radeon RX 6650 XT, RADV/Mesa 26.2.6; physical Vulkan with required VK_LAYER_KHRONOS_validation, ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, explicit Radeon ICD. The replay loader log confirms insertion of both the Khronos instance and device layers.

Baseline 89ac26614affe3040ea6220958a97f4c11e44d71 is clean main ba627802e2210187d417deb64c8f2fed8e33011f plus #11435 for its longer replay drain deadline. Change c31040f4eb4d6b129c7620f3f2da340e011ad053 adds this PR to that same baseline.

Two conflicts were resolved without dropping main's behavior:

  • nanResultF32: retain main's if (!ExactF32Arithmetic()) return result; before the incoming NanPropagateF32 implementation. The existing fast-f32 test remains in the gate.
  • SrtEvaluator.cpp: keep main's CompositeExtractU32x4 validity case and the incoming NanPropagateF32 case. The combined merge diff is in the evidence archive.

Matched focused gate: baseline 10/10, change 11/11, zero skipped, failed, or VUID- messages, and no missing-layer message. The common controls cover f32 NaN source order, constant-factor tininess, denormal flush, min/max NaNs, legacy FMA, FMA rounding, quieting, fast-f32 mode, shader-memory evaluation, and vector-window shape. Baseline contains eight physical-GPU tests plus two CPU groups; change contains nine physical-GPU tests plus two CPU groups, adding agc_driver_relative_indexing_bounded_values. Full commands, logs and JUnit are attached.

Bugsnax PPSA01503 v02.000.000: the same private 3840×2160 cave-entrance frame captured from main replays with both builds using --strict --no-synthesize --frames <output>. With this PR: one frame completed, zero unfinished submissions, zero pacing timeouts, zero failed/stale registrations, zero skipped MiB and zero synthesized waits. All three reference/replay BMP pairs are byte-identical by SHA-256. The baseline matched these same buffers too (#11435 validation). Protected inputs/libraries stayed unchanged and every test process exited.

One of this scene's expensive fragment programs compiles to 58,926 SPIR-V words on baseline and 65,918 with this PR: fewer selects but more control flow. Cold single-pass replay takes 46.549 versus 76.785 seconds, including preparation and pacing; those are not steady-state GPU times or native FPS. This confirms a real frame still renders exactly while also showing why static size and cold replay cannot establish a performance gain. Normal game-launch, same-scene FPS measurement remains outstanding; this is not full-suite, full-game, Windows or PS5-equivalence qualification.

Evidence archive, SHA-256 f2c45139c0cb15e14ba3d73877b4b98f9c54a3a30ef31737a8eed50b234c814f; download and all 18 inner files verified. Raw capture, requests, ISA/SPIRV, game data, saves and binaries remain private.

@JJenkx

JJenkx commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Native Bugsnax follow-up on the same RX 6650 XT: these repeats do not establish a stable FPS gain in this scene. This supplements the earlier pixel-exact replay/correctness result; it does not contradict the reported NVIDIA result for another title.

Clean main ba627802e2210187d417deb64c8f2fed8e33011f versus e50b06bdd22398db8020f0db7387347c0421866c, that same main plus this PR at e3b2b4c1f6bff3044d2c799fbb8f96a49276472a. No #11435 or other replay changes in either native build. Both use the same freshly built main relinker; all 799 files per SDK bank are hashed and immutable. Only the expected shader/test/debt source files differ, retaining main's exact-f32 guard and SRT validity case.

Machine: Ryzen 9 7950X, 32 threads, 128 GiB RAM, RX 6650 XT, RADV Mesa 26.2.6-arch1.1, Linux 7.2.11-arch1-1. Bugsnax PPSA01503 v02.000.000, 3840×2160 render resolution, saved rainy cave entrance. Separate fresh caches and writable runtimes; the same verified inactive save seed and Cross at30/50/70 seconds, held2s. No input after about73s. Reviewed snapshots at120/165/195 show the same cave/camera/scaffold/vegetation, with normal animated rain/lens/wind differences. Each whole arm uses its own FIFO turn and closes ordinarily at210s.

Official tools/trace_digest.py results, APS5_TRACE_SECONDS=130:30, normal settings without per-draw profiling or forced recipe disabling:

Run Commit Presents / window FPS Frame p50 / p99 ms GPU busy ms/present
A1 ba62780 601 / 30.047 s 20.002 49.951 / 54.057 48.241
B1 e50b06b 629 / 30.032 s 20.944 47.713 / 51.869 46.334
B2 e50b06b 623 / 30.016 s 20.755 48.070 / 53.340 46.540
A3 ba62780 634 / 30.022 s 21.118 46.934 / 53.411 46.671

Order was A1 → B1 → B2 → A3 for the four qualified measurements. The first pair is +4.71%; the reversed comparison is −1.71%. Main itself varies from20.00 to21.12 FPS, while the change gives20.94 and20.76. The small average difference sits inside that main-run spread: I cannot claim a repeatable improvement or a general regression from these two runs per variant.

All four qualified runs exit0, no trace drops, protected input/save/SDK/executable/module hashes unchanged, no remaining native processes, and the temporary udmabuf limit restored to64. The matched correctness gate on these exact clean-main/change sources passes10/11 groups (8/9 physical-GPU plus2 CPU), zero skipped or VUID errors, with actual Khronos instance/device insertion in both logs.

Exclusions, retained rather than overwritten: the initial harness rejected a valid symlinked library before measurement; the resolved-path check was corrected without changing source/SDK. An additional main run between B2 and A3 is excluded because an independent HTTP2 CPU test overlapped its capture by16.89s; it was allowed to close normally and replaced by A3 with no other builds/tests/trace processing during that run. Timing receipts establish no such overlap for any of the four qualified windows. No focus was forced; directX11 freshness checks are unavailable where the window was inactive, and that limitation is retained beside the reviewed compositor images.

Four native traces and exact summary lines, commands, reviewed screenshots, full logs, SDK provenance, matched gate/JUnit and exclusion receipts, SHA-256 64a9b4e63836b72b5978231c08ab24aa4d9fc29bef412ecf4e5f211e58002750; download and all69 inner files verified. This tests only the saved cave, not bridge/tutorial completion or audio/PS5 equivalence. No game capture memory, shader request/ISA/SPIRV, assets, saves or binaries are uploaded.

@JJenkx

JJenkx commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Native title measurement for public head e3b2b4c1f6b on Overcooked! All You Can Eat, PPSA01528 01.015.000.

I integrated this PR alone onto main f2d874c1fdcc as private head e966f5e317b2. The two source conflicts retain main's ExactF32Arithmetic() guard and CompositeExtractU32x4 evaluator case; the integration diff is attached. No unrelated shader or graphics changes are included.

Same machine: RX 6650 XT, RADV Mesa 26.2.6, Linux 7.2.11, Ryzen 9 7950X. Both runs use 3840×2160, the same six-file save seed/input route, fresh private shader/Mesa caches, and the first tutorial kitchen at the ingredient prompt (score 0, timer 01:40). Both before/after-window screenshots were reviewed; camera/positions match, while costume tints vary between runs. This is not pixel-equivalence evidence. Both traces use APS5_TRACE_SECONDS=280:20, APS5_PROFILE_GPU=1, APS5_PROFILE_DRAW=1; per-draw GPU timing and shader dumps are off.

Official tools/trace_digest.py results:

main main + this PR
Presents / window 450 / 20.025876 s 459 / 20.046052 s
Mean FPS 22.4709 22.8973
Frame p50 44.373 ms 43.431 ms
Frame p90 47.115 ms 46.554 ms
Frame p99 49.578 ms 52.790 ms
GPU busy / present 36.111 ms 34.205 ms
Trace drops none none

Conclusion: +1.90% mean FPS in one pair, with worse p99, does not establish a useful title-level speedup. I am not claiming one or repeating this unchanged pair; it falls below the predeclared 5% threshold for a reverse-order main repeat.

The candidate exits normally after 333.9 s; observer/harness also exit 0. Protected inputs, executable/modules and the 799-file SDK bank are unchanged; the shared import limit is restored, and no private native process remains. Thirteen host-work samples covering 278–304 s contain no compiler/test/profiler processes. Five focused candidate tests pass without skips or VUIDs, with the Khronos instance/device validation layer actually inserted.

The shader that dominates the kitchen's GPU time was also captured privately and recompiled offline: main 24,683 SPIR-V words / 639 selects / 71 conditional branches; this PR 27,442 / 479 / 215. These counts are diagnostic, not a performance claim.

Traces, official digests, integration diff and focused test logs. SHA-256: fcd3c77e46d78b9bbe57dffae374cef708e6fe5ad8ba1a2210385a50f72f750b. No proprietary shaders, requests, assets, saves or screenshots are included.

@Filip722

Filip722 commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

@josealissonbr I am evaluating a narrow normal-finite-constant FMul32 domain fold: omit only the impossible invalid-result canonicalization while preserving every source NaN payload/quieting check. Your head e3b2b4c1f6 replaces the same helper with NanPropagateF32, so the full overlap check correctly requires manual coordination.

This proof differs from conditional source checking. If your PR goes first, I would express the same narrow predicate at the existing structured node rather than carry a competing legacy helper edit. Could you confirm the preferred ordering or whether you would like the domain proof offered as a credited follow-up? No measured gain is claimed here.

AI-assisted: yes (Codex).

The concrete change is now available as draft #14892, including the isolated diff, arithmetic proof, matched focused hardware checks, a pinned-current-main native refresh and separately scoped ordinary gameplay evidence. The merge-order question remains open; that branch includes none of these overlapping PRs.

@Filip722

Filip722 commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Radeon gameplay validation of the complete existing change by josealissonbr, at author head e3b2b4c1f6bff3044d2c799fbb8f96a49276472a.

I integrated it on plain main 92d2fdc3438f83e39d624eb65f3195bf2701568c as e5f6ded. Both conditional NaN repair and bounded vector-window narrowing are included. The two integration resolutions retain main’s ExactF32Arithmetic guard and CompositeExtractU32x4 SRT validity behavior. This tests the complete PR; it does not isolate either mechanism or establish an executed branch-skip count.

Each study used six prospectively fixed, balanced independent run-level pairs and one warmup per arm. The positive initial screen selected the candidate for one fresh, separately frozen confirmation with the balanced launch order reversed. Results are reported separately, without pooling or additional pairs:

Study Main → complete PR, mean ms/frame Paired reduction 95% CI
Initial screen 21.129179 → 20.613925 0.515254 ms / 2.434528% 0.196995–0.833512 ms / 0.931429–3.937628%
Independent confirmation 21.116265 → 20.397929 0.718336 ms / 3.400955% 0.609787–0.826884 ms / 2.895957–3.905953%

The primary metric is each run’s original window.ms / presents, paired by run; intervals use Student-t with 5 degrees of freedom. All 24 timed runs and four warmups passed, with zero replacements. Every valid slow run is retained, including the negative first screen pair.

Scope: Sons of Sparta PPSA28997 v01.008.001, restored camp, physical internal 2560×1440, presentation 1920×1080, Radeon 760M / private RADV Mesa 26.2.6 + libdrm 2.4.133 / Linux 7.2.12. Exact arithmetic, normal GPL with optimized LTO, explicit pipeline journal OFF, default heap setting, and APS5_TRACE_EVENTS=524288 matched in both arms. This is not an ordinary-1080p, delivered-profile, NVIDIA, latest-main or additive-performance result.

Matched focused coverage passed all 11 groups per arm, including nine actual Vulkan execution groups with the Khronos layer loaded on the Radeon, plus shader-memory and vector-window groups. The author’s bounded-relative-index execution fixture was also compiled against plain main for a matched control. No skipped tests, missing-layer messages or VUID errors appeared. These are this integration’s tests, separate from the earlier contributor’s Radeon integration coverage.

Timing-only evidence with frozen protocols, exact source/configuration hashes, original summary lines, pinned upstream full digests, all unchanged original timing traces, and full remote byte/readback verification: initial screen and independent confirmation. Game-derived shaders, saves, screenshots, ISA, captures, logs and binaries remain private.

AI-assisted validation and analysis: yes (Codex). Credit for the optimization remains with josealissonbr.

@josealissonbr

Copy link
Copy Markdown
Contributor Author

Closing this PR. I no longer have the GPU (RTX 5070) that this work was developed, tested and measured on, so I can't test it or follow up on review anymore, and the PR is no longer useful from my side. Thanks for the reviews.

@Filip722

Filip722 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

@josealissonbr @boykopovar I would like to take over the integration, Linux/Radeon testing and review follow-up for this work, while retaining josealissonbr’s authorship and credit. Would you be comfortable reopening #12548 with that arrangement, or would you prefer a credited successor PR from my fork? I cannot reproduce the original RTX 5070 measurements, so those would remain explicitly attributed historical evidence.

There is independent evidence worth preserving: our complete-PR validation found a 2.43% mean frame-time reduction in a six-pair screen and 3.40% in a separate fresh six-pair confirmation (95% CI 2.90–3.91%). That is Sons of Sparta’s physical-1440p camp on Radeon 760M/private RADV 26.2.6, main 92d2fdc3438f versus credited integration e5f6ded23890, with 11 matched focused groups passing per arm. It is a whole-PR result, not attribution to either mechanism or a claim about current main.

Proposed continuation:

I rechecked main at 0eba5db30d8a; #10720 and #14892 are merged, but this PR’s two mechanisms are still absent. No new build or timing result is claimed in this offer. The preserved implementation and timing-only evidence remain available; no game-derived material needs to be published.

AI-assisted: yes (Codex).

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

Labels

agc libSceAgc* build docs needs rebase Conflicts with main, rebase needed perf Performance change shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants