Skip to content

perf(shader): replace linear scans with hash lookups in recompiler - #1610

Closed
silentone12725 wants to merge 1 commit into
boykopovar:mainfrom
silentone12725:perf/shader-linear-scan-eliminations
Closed

silentone12725 wants to merge 1 commit into
boykopovar:mainfrom
silentone12725:perf/shader-linear-scan-eliminations

Conversation

@silentone12725

@silentone12725 silentone12725 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • SPIR-V backend: add capabilitySet/extensionSet to SpirvEmitterState and use them instead of std::find over the supported-capability/extension spans (module setup, descriptors, image emitter).
  • SrtPlanBuilder/SrtEvaluator: track visited/visiting values in hash sets (the plan builder keeps the vector only for cycle-position lookup on an actual cycle).
  • Structurizer: precompute block order in an unordered_map instead of std::find inside std::sort comparators (was O(N^2 log N)).
  • EmbeddedVertexFetch: use a set for the add-PC membership test in the shared lambda.

No behavior change intended.

Test plan

  • python3 tools/check_conventions.py --base origin/main
  • Full build of shader_recompiler_agc_driver and the shader tests
  • agc_shader_control_flow_tests, agc_shader_memory_tests, agc_shader_fusion_tests, agc_shader_disk_cache_tests all pass
  • All 22 SPIR-V modules produced by the memory test pass spirv-val --target-env vulkan1.3
  • Build workflow run on the fork, dispatched on head 1feb8793: passed for Linux and Windows (run 37833581660). It is not in the PR checks because the upstream run for this head is waiting for maintainer approval (CI: 38 open PR heads are queued at action_required, so their PRs show no checks #1631).

Measured

Pattern benchmarks of the old and new loop shapes in isolation (g++ -O2, best of 5), not a whole-shader measurement:

  • SrtPlanBuilder visited tracking: 60.6 ms with a vector against 1.1 ms with a set at 20 000 values; 0.7 ms against 0.1 ms at 2 000.
  • Structurizer block order inside the sort: 3.0 ms against 0.16 ms at 5 000 blocks; no gain at 200 blocks.
  • Capability and extension lookups: about 6.5 ms against 4.0 ms per million lookups. A shader makes few such checks, so the gain is small, and the sets are built once per SpirvEmitterState.
  • EmbeddedVertexFetch shared: slower with a set at 8 addPcs (0.17 ms against 0.08 ms for 50 000 instructions), faster at 64 (0.18 ms against 0.47 ms).

Changes since the first revision

  • Description only: the test plan now lists the full build, the four shader suites and the SPIR-V validation, and the measurements above are added. The code is unchanged.

Capability and extension checks in the SPIR-V backend, SRT walker
visited/visiting tracking, structurizer block ordering and embedded
vertex fetch PC matching all used std::find over vectors on hot paths.
Use unordered sets/maps instead; behavior is unchanged.
@oneandonlydean

Copy link
Copy Markdown
Collaborator

Closing: perf changes need before/after numbers for the change itself (#218), and the capability and extension lists here hold a handful of entries, where a hash set isn't faster than a scan. If one of these scans shows up in a profile, please reopen with that measurement for it alone.

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

Labels

shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants