Skip to content

perf(agc): copy a descriptor region behind pending GPU work on the GPU whatever its size - #13263

Draft
EagleBearerYS wants to merge 2 commits into
boykopovar:mainfrom
EagleBearerYS:fix/agc-buffer-upload-pending-gpu-copy
Draft

EagleBearerYS wants to merge 2 commits into
boykopovar:mainfrom
EagleBearerYS:fix/agc-buffer-upload-pending-gpu-copy

Conversation

@EagleBearerYS

@EagleBearerYS EagleBearerYS commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

What

When a dispatch's or draw's build uploads a descriptor region that isn't aligned inside its host import, the driver can copy it on the GPU from the import (recordGpuCopies) instead of reading it on the CPU. On main that GPU copy is allowed only up to APS5_GPU_COPY_MAX_KIB (1024 KiB by default, gpuCopyEligible). A larger region takes the CPU copy in copyRegion, and its GuestMemory::Read goes through the flush hook. So when GPU work is still pending over the region, the CPU waits for it, under the GPU mutex in UploadFinish:

  • a pending write: a pending-write sync, which submits the open batch;
  • pending storage results or unit shadows: a recorded-store sync.

This change copies such a region on the GPU whatever its size, when there is pending GPU work over it: a pending write, pending storage results, or a unit shadow.

Why that's safe: the bound isn't there for correctness. The GPU copy uses the same host-visible buffer as the CPU copy, and for a region with no GPU work over it the CPU copy never waits, so keeping that region on the CPU stays the cheaper choice. Behind GPU work, the GPU path already records everything the CPU would have waited for:

  • order: the copy goes into the open batch after its producer, behind the leading barrier;
  • queued key and label stores: they're recorded first;
  • pending storage results: they're recorded ahead of the copy, and unit shadows are published;
  • writes that land on the CPU: a copied buffer's write-back and completion labels are synced at the start of UploadFinish.

How it decides:

  • New copyBehindGpuWork(region, locked): holds for a GPU-copyable region the active recorder has GPU work over.
  • UploadPrepare: asks the recorder's published pending-write snapshot, which needs no lock.
  • UploadFinish: asks the recorder under the GPU mutex.
  • A region the snapshot flagged but the recorder no longer sees as pending: takes the CPU copy, which then doesn't wait.

Unchanged:

  • regions below the bound;
  • regions behind no GPU work;
  • a region no single import covers;
  • sparse regions;
  • APS5_CPU_COPIES=1, which disables every GPU copy.

The APS5_GPU_COPY_MAX_KIB row in ENVIRONMENT.md now says the cap doesn't apply behind GPU work.

Pending:

  • whether Resident Evil Village (PPSA01556)'s uploads take this path (below);
  • then a Village pair.

Resident Evil Village (PPSA01556)

Static menu, profiled boot (APS5_PROFILE_DRAW=1) on main ebb4075 plus #12478. Its [hooksync] lines show these buffer-upload waits per 10 s:

  • pending-write syncs: 0x0 DISPATCH_DIRECT buffer-upload, 65 syncs, 238 ms, average access 11,632 KiB over an average noted range of 3,162 KiB;
  • recorded-store syncs: 0x28 DISPATCH_DIRECT buffer-upload, 29 syncs, 364 ms.

Not confirmed yet: whether those regions lie inside one host import, which is the case this change covers, or cross several registered allocations, which it doesn't. A profiled boot with this change will tell, from its [buffers] line and the buffer-upload syncs left.

Tested

  • agc_buffer_upload_pending_gpu_copy (new), run as agc_driver_recorder_tests --pending-upload-gpu-copy-only. The full recorder run includes it too.
    • Setup: a 4 MiB write-watched, host-imported block. A vkCmdCopyBuffer in the open batch writes a 1 MiB pattern at +1 MiB, noted as a pending write.
    • The upload: under the GPU mutex, the build uploads a 3 MiB region at +4100. That's misaligned for storage buffers and three times the old bound.
    • It must make 0 flush-hook waits and 0 submissions, with the producer still pending.
    • The bytes: a GPU copy of the descriptor's bound range must hold the producer's pattern over its megabyte and the original bytes elsewhere. Guest memory must hold the pattern after the sync.
  • Red (main plus the test only): "the upload of a misaligned 3 MiB region over a pending GPU write waited for it on the CPU (1 flush-hook waits, 1 submissions)".
  • Linux (Ubuntu 24.04, GCC 13.3, Release, CI's flags, lavapipe, as an unprivileged user):
    • the new test: ×10, 10 of 10 passed;
    • ctest -R '^agc' once, 1,136 tests: 1,060 passed, 75 skipped, 1 failed. The one failure, agc_driver_image_sample_force_degamma, is that VM's known llvmpipe JIT illegal instruction (vpdpwssd) and fails on main there too.
  • GitHub, ×10 on both runners (run): the new test and the copy and staging tests around it.
    • Linux (llvmpipe 20.1.2): 78 tests, all 10 runs passed, 8 skipped. With main's code, agc_buffer_upload_pending_gpu_copy fails with the message above, and so does agc_driver_recorder, the full recorder run that includes it.
    • Windows: 94 tests, 4 run and passed, 90 skipped. The runner has no Vulkan device, so this test skips there; no Windows red is claimed.
    • Suites: libc and libkernel pass: 198 and 304 tests on Linux, 225 and 326 on Windows.
  • Validation layer (Khronos validation on GitHub's Linux runner, llvmpipe 20.1.2, run): the same 78 tests with the fix report one VUID, VUID-VkDeviceCreateInfo-pNext-pNext, which main's run reports too, so the fix adds none. The layer loaded in both runs. In this mode main's side runs main's own tree, so the new test is only in the fix's side.
  • Checks: check_conventions.py and check_test_registration.py pass. MinGW-w64 -fsyntax-only shows no new diagnostic.

Overlap:

  • No open pull request changes the bound, the eligibility check, or the upload's CPU read.
  • perf(agc): reuse immutable buffer copies and batch uploads #1364 (TibixDev, open) reads the region through recorder->ReadBuffer. That's still a CPU read under the same site, so it composes with this change.
  • Utku Halis's e10f59a ("copy buffers that span adjacent host imports on the GPU", in Opened here by mistake #12082, which its author closed) handles the complementary case: a region outside any one import.
  • 5a09407, a merge of main 0a148be (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_recorder_tests.cmake (+6 lines). Nothing else conflicted, and apart from the move this PR's diff is unchanged. With -DBUILD_TESTING=ON, ctest -N gives 3106 tests: main's 3105 plus its 1 test, each listed once. The tests of this PR's verify set pass 10 runs in a row. Linux: 5 run, 5 pass, 0 skip, 0 fail. Windows: 5 run, 0 pass, 5 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.

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: llvmpipe (Mesa 25.2.8, LLVM 20.1.2) on GitHub's Linux runner and lavapipe on Ubuntu 24.04; no hardware GPU yet
  • AI-assisted: yes

…U whatever its size

A misaligned descriptor region inside a host import is copied out of the
import by the GPU only up to APS5_GPU_COPY_MAX_KIB (1 MiB). A larger one
was read on the CPU, and when a pending GPU write, pending storage results
or a unit shadow covered it, that read waited in the flush hook for the
producer's batch (the [hooksync] "buffer-upload" syncs).

Such a region now takes the GPU copy whatever its size: the copy is
recorded after the producer in batch order, behind the barrier and the
pending-results flush the GPU path already records, so the bytes are the
same and the CPU does not wait. UploadFinish asks the recorder under the
GPU mutex; UploadPrepare, which holds no lock, asks the published
pending-write snapshot. Larger regions behind no GPU work keep the CPU
copy, which never waits for them. Completion write-backs and labels over
the range are still synced first by CompletePendingCpuWrites, so a pending
write the copy sees has landed in the import on the GPU.

The test (agc_buffer_upload_pending_gpu_copy) uploads a 3 MiB misaligned
region over a GPU write still in the open batch: the upload makes no
flush-hook wait and no submission, and a GPU read of the bound buffer
holds the producer's bytes.
@github-actions github-actions Bot added perf Performance change perf numbers missing perf pull request without a before and after summary line labels Oct 30, 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.

@github-actions

github-actions Bot commented Oct 30, 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 1368 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 1395 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 1896 docs/dev/ENVIRONMENT.md
PR 4472 docs/dev/ENVIRONMENT.md
PR 5021 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 5925 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6186 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 6187 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6188 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6192 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6209 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6481 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6918 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6924 docs/dev/ENVIRONMENT.md
PR 7085 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
PR 7449 docs/dev/ENVIRONMENT.md
PR 7457 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 7514 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/ENVIRONMENT.md
PR 7604 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 8004 docs/dev/ENVIRONMENT.md
PR 8484 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 9012 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/ENVIRONMENT.md
PR 9289 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 9345 docs/dev/ENVIRONMENT.md
PR 9356 docs/dev/ENVIRONMENT.md
PR 9387 docs/dev/ENVIRONMENT.md
PR 9508 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 9852 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/ENVIRONMENT.md
PR 9884 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
PR 10193 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 10442 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 10678 docs/dev/ENVIRONMENT.md
PR 10757 docs/dev/ENVIRONMENT.md
PR 10894 docs/dev/ENVIRONMENT.md
PR 10920 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 11435 docs/dev/ENVIRONMENT.md
PR 11436 docs/dev/ENVIRONMENT.md
PR 12157 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 12324 docs/dev/ENVIRONMENT.md
PR 12544 docs/dev/ENVIRONMENT.md
PR 12746 docs/dev/ENVIRONMENT.md
PR 12848 docs/dev/ENVIRONMENT.md
PR 12849 docs/dev/ENVIRONMENT.md
PR 12970 docs/dev/ENVIRONMENT.md
PR 13148 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 13486 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 13707 docs/dev/ENVIRONMENT.md
PR 13793 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 13809 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 13863 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 13920 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 13928 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 13929 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 14051 docs/dev/ENVIRONMENT.md
PR 14344 docs/dev/ENVIRONMENT.md
PR 15059 docs/dev/ENVIRONMENT.md
PR 15136 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 15169 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 15296 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 15302 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 15529 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
docs/dev/ENVIRONMENT.md
PR 15548 docs/dev/ENVIRONMENT.md
PR 15570 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/ENVIRONMENT.md

@github-actions github-actions Bot added build docs agc libSceAgc* needs rebase Conflicts with main, rebase needed labels Oct 31, 2026
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 Nov 1, 2026

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

The perf(agc) title makes a speed claim, and the evidence for it does not meet the bar yet.

  1. No tools/trace_digest.py summaries. The only numbers are APS5_PROFILE_DRAW=1 [hooksync] lines for main ("65 syncs, 238 ms", "29 syncs, 364 ms" per 10 s). Those say the waits exist, not that removing them makes the scene faster. Please attach trace_digest summaries of main and of this branch from the same machine and scene (frame p50/p90/p99, GPU busy per present), with the RE Village menu named by title ID and a log line showing the large pending-write upload is reached on main.

  2. No hardware GPU. "GPUs tested" lists llvmpipe/lavapipe only. The change turns a CPU Read into a vkCmdCopyBuffer of unbounded size into the open batch, so the cost moves to the GPU timeline. On a discrete card that copy reads from a host-imported system-memory range over PCIe, and with APS5_GPU_COPY_MAX_KIB removed as a bound for this case a 3+ MiB (or much larger) descriptor range is copied on every build behind pending work. Please run it on a real GPU and show GPU busy per present does not rise.

  3. The size bound is removed, not replaced. copyBehindGpuWork has no upper limit and no per-frame budget. Is there a case where the pending overlap is a few bytes inside a very large descriptor range (PendingWriteOverlaps / AnyShadowedOverlaps on region.begin..region.end)? Then the whole region is GPU-copied to avoid waiting for a small producer. A test with a small pending write inside a large region, counting copied bytes, would show whether that is bounded.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@CnRJay, thanks. This stays a draft until a pair decides the speed claim, and points 1 and 2 are what it needs before it's ready: trace_digest.py summaries of main and of this branch from the same machine and scene, on a hardware GPU, with GPU busy per present.

On point 3, from the code: as you say, the size bound is removed for this case, not replaced. When a pending write, a pending storage result or a shadowed range overlaps any part of the region, the GPU copies the whole region behind that work. For a region over the bound, main reads the same whole region on the CPU after waiting for the producer. So this PR changes where the copy runs and drops the wait, not how many bytes are copied. A test with a small pending write inside a large region, counting the copied bytes, would show that, and it's needed before this is marked ready too.

@mrfelek

mrfelek commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

PPSA22408 (Hot Wheels Infinite Rush), garage menu: no effect from this PR, and where the GPU copy is skipped

Linux, RTX 3080 Ti (NVIDIA 615.71.09), Ubuntu 26.10, Linux 7.3, Release. Same route into the garage each run, default settings, headless, APS5_DIAG_SYNC=1 in both arms.

Both arms contain the same local diagnostic (a stack counter on the flush hook's GPU waits). It is not part of any PR. A and B were alternated, two runs each, 266 s per run, and the table is the garage window (about 110 s on).

A B
Presents per second 6.72, 6.75 6.75, 6.67
GPU busy per present 86.1, 86.2 ms 86.1, 86.2 ms
Flush-hook syncs per 10 s 1,970 / 1,934 1,950 / 1,942
Time waited in them per 10 s 6.22 / 6.21 s 6.21 / 6.11 s

The row this PR targets is unchanged. In the first pair of runs, GuestBufferMemory::copyRegion called from UploadFinish (a CPU read of 648,000 bytes, a pending-write sync) is 67 syncs and 1,046 ms per 10 s in A and 67 syncs and 1,047 ms in B. That is about 16 ms per frame.

Why the GPU copy isn't reached. I printed the region at the copyRegion call in the steady garage state (sampled every 200th call):

importCovers=0 sparse=0 hostBacked=0 writable=1 eligible=1 behindSnapshot=1 anyPending=1 direct=0 recorder=1

The region passes this PR's eligibility test (eligible=1, with pending GPU work over it), but no host import covers it, so entry is null and the GPU-copy branch is never considered. The region's address also moves between frames. The imports aren't being refused (refused 0, failed 0 at shutdown). I haven't yet checked why importAccess makes none for it. I suspect the guest-allocation lease doesn't cover the whole region, but that is a guess.

So for this title the limit isn't the size cap or the eligibility rule. It is import coverage of this region. A question for the author: should the GPU copy be possible without a covering import, for example from a copy of the guest bytes?

I can paste the four aps5-summary.jsonl lines (A and B) if they help with the perf label.

AI-assisted.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@mrfelek, thanks for the pair. It answers the question for Hot Wheels Infinite Rush (PPSA22408): this PR doesn't reach that region.

Your guess about the lease matches the code. In UploadFinish, a region with no import yet gets one from importAccess (GuestBufferMemory.cpp L2437-2440 at this PR's head 5a09407). That function makes an import only when the registered allocations cover the whole region (runCovers(lease, begin, end)); otherwise it only looks up an existing one. So entry stays null and the region takes the CPU copy. That's the "a region no single import covers" case in the description, which this PR leaves as it is.

On a GPU copy from a copy of the guest bytes: making that copy is the CPU read this PR avoids. The bytes it needs are the ones the pending write produces, so taking them on the CPU means waiting for that write first, as copyRegion does now. The GPU copy avoids the wait only because its source is the import the producer writes through.

The case that can still go on the GPU is a region that crosses the boundary between two registered allocations, each with its own import. Utku Halis's e10f59a (in #12082, which its author closed) splits such a region into the imports it covers and copies it piece by piece. We keep it, with a follow-up for the pending-work case, on fix/agc-buffer-upload-pending-gpu-copy-spans, on top of this PR's first head. Whether it applies here depends on why runCovers fails: if the region crosses two registered allocations, it would apply; if part of it runs past registered memory, nothing here would.

The summary lines aren't needed for this one, since the pair shows no change. This stays a draft: its speed claim still needs a Resident Evil Village (PPSA01556) pair, which isn't planned yet.

This branch has not been deployed

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

Labels

agc libSceAgc* build docs perf numbers missing perf pull request without a before and after summary line perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants