Skip to content

perf(agc): fill the device proc table before objects copy the context - #853

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
meh7an:perf/agc-proc-table-before-context-copies
Oct 8, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
meh7an:perf/agc-proc-table-before-context-copies

Conversation

@meh7an

@meh7an meh7an commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

What

VulkanDevice filled its DeviceFunctions table only after creating the buffer pool, pipeline cache, detiler, texture cache, color transfer, descriptor cache and recorder. Each of those keeps its own copy of the Graphics::Context, so their copies have no table and look every entry point up by name through vkGetDeviceProcAddr on each call, for example vkAllocateDescriptorSets for every draw's descriptor sets.

FillDeviceFunctions only needs the device and vkGetDeviceProcAddr, so the table is now filled right after the command pool, before any of those objects is made. The cached context is still built after the recorder, as before.

Tested

Windows 11, MinGW GCC 15.2, RTX 2080 Ti. This branch builds, and the 165 agc driver, recompiler and execution test targets pass with it stacked on the other changes I'm sending.

Measured alone on Sonic Origins Plus's heaviest menu page (about 1,650 draws per frame), as asked. The base is main at this PR's base (5895ea7) plus the commits my branch needs to boot this title and to sample it (a launcher script, the title's boot fixes, the process sampler; none of them are in this PR), against the same base with this commit on top. Three interleaved rounds, each the median of six FPS readings:

Round 1 Round 2 Round 3 Mean
base 11.82 11.52 11.71 11.68 FPS (85.6 ms)
with this PR 12.19 11.95 12.07 12.07 FPS (82.9 ms)

About 2.7 ms per frame, ahead in every round. In a 15 s profile of the page, Context::Function looking up vkAllocateDescriptorSets by name (the loader's vkGetDeviceProcAddr under it) took 22 of 2,553 AGC worker samples (0.9%) on the base and none with this PR. The loader's whole share of the worker went from 1.18% to 0.53%; what is left comes from BuildVertexInputLayout.

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 in TechnicalDebt
  • 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
  • AI-assisted: yes

@github-actions github-actions Bot added the agc libSceAgc* label Oct 6, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

Thanks. Filling the table earlier looks exact to me: FillDeviceFunctions only needs the device and vkGetDeviceProcAddr, and buildContext() already copes with the recorder, caches and empty buffer being null at that point.

Two things:

  • Performance PRs need before/after numbers for the change itself (the owner asked for this on perf(shader): cut hot-path overhead in recompile cache lookups #218). The 48.0 to 43.6 ms figure is for 15 changes together. Could you measure main against main plus this PR alone on the same page? The mean frame time over a few runs is enough, or the vkGetDeviceProcAddr share of the AGC worker profile.
  • The PR rewrites the existing comment into two new comment blocks. CONVENTIONS only allows comments for technical debt, #endif and namespace ends, so please drop both blocks rather than reword them.

@meh7an
meh7an force-pushed the perf/agc-proc-table-before-context-copies branch from b7c78ea to 7ef0d4c Compare October 7, 2026 15:20
@meh7an

meh7an commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Dropped both comment blocks and force-pushed. Measured alone, the page goes from 85.6 to 82.9 ms per frame, ahead in all three interleaved rounds, and the per-draw vkAllocateDescriptorSets lookup through vkGetDeviceProcAddr (0.9% of the AGC worker on the base) is gone from the profile. The numbers are in the description.

@Celegans12

Copy link
Copy Markdown
Contributor

I ran Ghost of Yōtei (PPSA26344 v1.008) for an hour with this PR (7ef0d4c) and APS5_PROFILE_DRAW=1, mostly to watch the [vk] deviceProc lookups inside the device call counter, and it went down less than I expected.

In the open world it came to about 19 lookups per dispatch, against about 25 in our previous run without the PR. Up to the world, through the intro, it was about 23 per dispatch in both runs. I had expected it to drop close to zero once the table is filled before the caches and the recorder copy the context, so something else still resolves device functions inside device calls. I haven't looked into which calls those are. I didn't see any regression from the PR either: no Vulkan error and no FATAL in the hour.

If it helps, I can rerun with a trace of the names being looked up, if you point me at the place you'd hook it.

Details

Windows 11, RTX 3080 Laptop. With the PR: our integration tree on main c8a2f06 + this PR at 7ef0d4c. Without: the previous integration build. The counter is cumulative, so the world numbers are deltas between the first line after the world loads and the last line of the run.

With the PR (world from 412 s; 4.86 M lookups over 255 k dispatches = 19.1):

[vk] deviceProc lookups inside the device call: 2243044 (22.99 per dispatch); ...   (412 s)
[vk] deviceProc lookups inside the device call: 7104228 (20.16 per dispatch); ...   (3591 s)

Without it (world from 790 s; 3.06 M lookups over 122 k dispatches = 25.0):

[vk] deviceProc lookups inside the device call: 2273663 (23.23 per dispatch); ...   (790 s)
[vk] deviceProc lookups inside the device call: 5336254 (24.23 per dispatch); ...   (2397 s)

@oneandonlydean
oneandonlydean merged commit 6bdd6ef into boykopovar:main Oct 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants